diff -Naurd ../nethack-3.4.0/include/amiconf.h ./include/amiconf.h --- ../nethack-3.4.0/include/amiconf.h Wed Mar 20 23:42:42 2002 +++ ./include/amiconf.h Mon Feb 24 15:25:05 2003 @@ -38,7 +38,7 @@ #define NOCWD_ASSUMPTIONS /* Allow paths to be specified for HACKDIR, LEVELDIR, SAVEDIR, BONESDIR, DATADIR, - SCOREDIR, LOCKDIR, and CONFIGDIR. */ + SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */ /* data librarian defs */ #ifndef NOCWD_ASSUMPTIONS @@ -47,6 +47,8 @@ #else # define DLBFILE "nhdat" /* main library */ # define DLBFILE2 "nhsdat" /* sound library */ +#endif + #define FILENAME_CMP stricmp /* case insensitive */ #ifndef __SASC_60 diff -Naurd ../nethack-3.4.0/include/artilist.h ./include/artilist.h --- ../nethack-3.4.0/include/artilist.h Wed Mar 20 23:42:42 2002 +++ ./include/artilist.h Mon Feb 24 15:25:05 2003 @@ -107,7 +107,7 @@ A("Werebane", SILVER_SABER, (SPFX_RESTR|SPFX_DFLAG2), 0, M2_WERE, - PHYS(5,0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 1500L ), + PHYS(5,0), DFNS(AD_WERE), NO_CARY, 0, A_NONE, NON_PM, NON_PM, 1500L ), A("Grayswandir", SILVER_SABER, (SPFX_RESTR|SPFX_HALRES), 0, 0, diff -Naurd ../nethack-3.4.0/include/color.h ./include/color.h --- ../nethack-3.4.0/include/color.h Wed Mar 20 23:42:43 2002 +++ ./include/color.h Mon Feb 24 15:25:05 2003 @@ -46,6 +46,7 @@ #define HI_PAPER CLR_WHITE #define HI_GLASS CLR_BRIGHT_CYAN #define HI_MINERAL CLR_GRAY +#define DRAGON_SILVER CLR_BRIGHT_CYAN #define HI_ZAP CLR_BRIGHT_BLUE #endif /* COLOR_H */ diff -Naurd ../nethack-3.4.0/include/config.h ./include/config.h --- ../nethack-3.4.0/include/config.h Wed Mar 20 23:42:43 2002 +++ ./include/config.h Mon Feb 24 15:25:05 2003 @@ -83,7 +83,9 @@ #endif #ifdef QT_GRAPHICS +# define DEFAULT_WC_TILED_MAP /* Default to tiles if users doesn't say wc_ascii_map */ # define USER_SOUNDS /* Use sounds */ +# define USER_SOUNDS_REGEX # define USE_XPM /* Use XPM format for images (required) */ # define GRAPHIC_TOMBSTONE /* Use graphical tombstone (rip.ppm) */ # ifndef DEFAULT_WINDOW_SYS @@ -131,9 +133,10 @@ /* * Section 2: Some global parameters and filenames. - * Commenting out WIZARD, LOGFILE, or NEWS removes that feature - * from the game; otherwise set the appropriate wizard name. - * LOGFILE and NEWS refer to files in the playground. + * Commenting out WIZARD, LOGFILE, NEWS or PANICLOG removes that + * feature from the game; otherwise set the appropriate wizard + * name. LOGFILE, NEWS and PANICLOG refer to files in the + * playground. */ #ifndef WIZARD /* allow for compile-time or Makefile changes */ @@ -147,6 +150,7 @@ #define LOGFILE "logfile" /* larger file for debugging purposes */ #define NEWS "news" /* the file containing the latest hack news */ +#define PANICLOG "paniclog" /* log of panic and impossible events */ /* * If COMPRESS is defined, it should contain the full path name of your diff -Naurd ../nethack-3.4.0/include/decl.h ./include/decl.h --- ../nethack-3.4.0/include/decl.h Wed Mar 20 23:42:44 2002 +++ ./include/decl.h Mon Feb 24 15:25:05 2003 @@ -270,16 +270,16 @@ *const c_silver, *const c_blue, *const c_purple, *const c_white; } c_color_names; -#define Black c_color_names.c_black -#define amber c_color_names.c_amber -#define golden c_color_names.c_golden -#define light_blue c_color_names.c_light_blue -#define red c_color_names.c_red -#define green c_color_names.c_green -#define silver c_color_names.c_silver -#define blue c_color_names.c_blue -#define purple c_color_names.c_purple -#define White c_color_names.c_white +#define NH_BLACK c_color_names.c_black +#define NH_AMBER c_color_names.c_amber +#define NH_GOLDEN c_color_names.c_golden +#define NH_LIGHT_BLUE c_color_names.c_light_blue +#define NH_RED c_color_names.c_red +#define NH_GREEN c_color_names.c_green +#define NH_SILVER c_color_names.c_silver +#define NH_BLUE c_color_names.c_blue +#define NH_PURPLE c_color_names.c_purple +#define NH_WHITE c_color_names.c_white /* The names of the colors used for gems, etc. */ E const char *c_obj_colors[]; @@ -337,7 +337,7 @@ #endif /* xxxexplain[] is in drawing.c */ -E const char *monexplain[], *invisexplain, *objexplain[], *oclass_names[]; +E const char * const monexplain[], invisexplain[], * const objexplain[], * const oclass_names[]; /* Some systems want to use full pathnames for some subsets of file names, * rather than assuming that they're all in the current directory. This @@ -348,11 +348,12 @@ #define LEVELPREFIX 1 #define SAVEPREFIX 2 #define BONESPREFIX 3 -#define DATAPREFIX 4 +#define DATAPREFIX 4 /* this one must match hardcoded value in dlb.c */ #define SCOREPREFIX 5 #define LOCKPREFIX 6 #define CONFIGPREFIX 7 -#define PREFIX_COUNT 8 +#define TROUBLEPREFIX 8 +#define PREFIX_COUNT 9 /* used in files.c; xxconf.h can override if needed */ # ifndef FQN_MAX_FILENAME #define FQN_MAX_FILENAME 512 diff -Naurd ../nethack-3.4.0/include/display.h ./include/display.h --- ../nethack-3.4.0/include/display.h Wed Mar 20 23:42:44 2002 +++ ./include/display.h Mon Feb 24 15:25:05 2003 @@ -125,6 +125,7 @@ /* * canseeself() + * senseself() * * This returns true if the hero can see her/himself. * @@ -132,7 +133,8 @@ * invisible. If not, then we don't need the check. */ #define canseeself() (Blind || u.uswallow || (!Invisible && !u.uundetected)) - +#define senseself() (canseeself() || Infravision || Unblind_telepat || \ + Detect_monsters) /* * random_monster() @@ -192,28 +194,22 @@ * _if_ the hero can be seen have already been done. */ #ifdef STEED -#define display_self() \ - show_glyph(u.ux, u.uy, \ - (u.usteed && mon_visible(u.usteed)) ? \ - ridden_mon_to_glyph(u.usteed) : \ - youmonst.m_ap_type == M_AP_NOTHING ? \ - hero_glyph : \ - youmonst.m_ap_type == M_AP_FURNITURE ? \ - cmap_to_glyph(youmonst.mappearance) : \ - youmonst.m_ap_type == M_AP_OBJECT ? \ - objnum_to_glyph(youmonst.mappearance) : \ - /* else M_AP_MONSTER */ monnum_to_glyph(youmonst.mappearance)) +#define maybe_display_usteed (u.usteed && mon_visible(u.usteed)) ? \ + ridden_mon_to_glyph(u.usteed) : #else +#define maybe_display_usteed /* empty */ +#endif + #define display_self() \ show_glyph(u.ux, u.uy, \ + maybe_display_usteed /* else */ \ youmonst.m_ap_type == M_AP_NOTHING ? \ - hero_glyph : \ + hero_glyph : \ youmonst.m_ap_type == M_AP_FURNITURE ? \ cmap_to_glyph(youmonst.mappearance) : \ youmonst.m_ap_type == M_AP_OBJECT ? \ objnum_to_glyph(youmonst.mappearance) : \ /* else M_AP_MONSTER */ monnum_to_glyph(youmonst.mappearance)) -#endif /* * A glyph is an abstraction that represents a _unique_ monster, object, @@ -314,10 +310,12 @@ #define ridden_monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_RIDDEN_OFF) #define petnum_to_glyph(mnum) ((int) (mnum) + GLYPH_PET_OFF) -/* The hero's glyph when seen as a monster. Could also be... - * mon_to_glyph(Upolyd || Race_if(PM_HUMAN) ? u.umonnum : urace.malenum) +/* The hero's glyph when seen as a monster. */ -#define hero_glyph monnum_to_glyph(u.umonnum) +#define hero_glyph \ + monnum_to_glyph((Upolyd || !iflags.showrace) ? u.umonnum : \ + (flags.female && urace.femalenum != NON_PM) ? urace.femalenum : \ + urace.malenum) /* diff -Naurd ../nethack-3.4.0/include/dlb.h ./include/dlb.h --- ../nethack-3.4.0/include/dlb.h Wed Mar 20 23:42:44 2002 +++ ./include/dlb.h Mon Feb 24 15:25:05 2003 @@ -125,12 +125,12 @@ #endif #define RDTMODE "r" -#if (defined(MSDOS) || defined(WIN32) || defined(TOS)) && defined(DLB) +#if (defined(MSDOS) || defined(WIN32) || defined(TOS) || defined(OS2)) && defined(DLB) #define WRTMODE "w+b" #else #define WRTMODE "w+" #endif -#if (defined(MICRO) && !defined(AMIGA)) || defined(THINK_C) || defined(__MWERKS__) +#if (defined(MICRO) && !defined(AMIGA)) || defined(THINK_C) || defined(__MWERKS__) || defined(WIN32) # define RDBMODE "rb" # define WRBMODE "w+b" #else diff -Naurd ../nethack-3.4.0/include/extern.h ./include/extern.h --- ../nethack-3.4.0/include/extern.h Wed Mar 20 23:42:46 2002 +++ ./include/extern.h Mon Feb 24 15:25:05 2003 @@ -39,7 +39,6 @@ E boolean NDECL(next_to_u); E struct obj *FDECL(get_mleash, (struct monst *)); E void FDECL(check_leash, (XCHAR_P,XCHAR_P)); -E boolean FDECL(wield_tool, (struct obj *)); E boolean FDECL(um_dist, (XCHAR_P,XCHAR_P,XCHAR_P)); E boolean FDECL(snuff_candle, (struct obj *)); E boolean FDECL(snuff_lit, (struct obj *)); @@ -62,6 +61,8 @@ E void FDECL(artifact_exists, (struct obj *,const char *,BOOLEAN_P)); E int NDECL(nartifact_exist); E boolean FDECL(spec_ability, (struct obj *,unsigned long)); +E boolean FDECL(confers_luck, (struct obj *)); +E boolean FDECL(arti_reflects, (struct obj *)); E boolean FDECL(restrict_name, (struct obj *,const char *)); E boolean FDECL(defends, (int,struct obj *)); E boolean FDECL(protects, (int,struct obj *)); @@ -109,7 +110,7 @@ E void FDECL(set_bc, (int)); E void FDECL(move_bc, (int,int,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P)); E boolean FDECL(drag_ball, (XCHAR_P,XCHAR_P, - int *,xchar *,xchar *,xchar *,xchar *, boolean *)); + int *,xchar *,xchar *,xchar *,xchar *, boolean *,BOOLEAN_P)); E void FDECL(drop_ball, (XCHAR_P,XCHAR_P)); E void NDECL(drag_down); @@ -171,6 +172,7 @@ E int FDECL(getdir, (const char *)); E void NDECL(confdir); E int FDECL(isok, (int,int)); +E int FDECL(get_adjacent_loc, (const char *, const char *, XCHAR_P, XCHAR_P, coord *)); E const char *FDECL(click_to_cmd, (int,int,int)); E char NDECL(readchar); #ifdef WIZARD @@ -382,6 +384,7 @@ E void NDECL(glibr); E struct obj *FDECL(some_armor,(struct monst *)); E void FDECL(erode_armor, (struct monst *,BOOLEAN_P)); +E struct obj *FDECL(stuck_ring, (struct obj *,int)); E void NDECL(reset_remarm); E int NDECL(doddoremarm); E int FDECL(destroy_arm, (struct obj *)); @@ -577,12 +580,12 @@ E void FDECL(losexp, (const char *)); E void NDECL(newexplevel); E void FDECL(pluslvl, (BOOLEAN_P)); -E long NDECL(rndexp); +E long FDECL(rndexp, (BOOLEAN_P)); /* ### explode.c ### */ E void FDECL(explode, (int,int,int,int,CHAR_P,int)); -E void FDECL(scatter, (int, int, int, unsigned int, struct obj *)); +E long FDECL(scatter, (int, int, int, unsigned int, struct obj *)); E void FDECL(splatter_burning_oil, (int, int)); /* ### extralev.c ### */ @@ -595,19 +598,21 @@ /* ### files.c ### */ +E char *FDECL(fname_encode, (const char *, CHAR_P, char *, char *, int)); +E char *FDECL(fname_decode, (CHAR_P, char *, char *, int)); E const char *FDECL(fqname, (const char *, int, int)); -E FILE *FDECL(fopen_datafile, (const char *,const char *,BOOLEAN_P)); +E FILE *FDECL(fopen_datafile, (const char *,const char *,int)); E boolean FDECL(uptodate, (int,const char *)); E void FDECL(store_version, (int)); #ifdef MFLOPPY E void NDECL(set_lock_and_bones); #endif E void FDECL(set_levelfile_name, (char *,int)); -E int FDECL(create_levelfile, (int)); -E int FDECL(open_levelfile, (int)); +E int FDECL(create_levelfile, (int,char *)); +E int FDECL(open_levelfile, (int,char *)); E void FDECL(delete_levelfile, (int)); E void NDECL(clearlocks); -E int FDECL(create_bonesfile, (d_level*,char **)); +E int FDECL(create_bonesfile, (d_level*,char **, char *)); #ifdef MFLOPPY E void NDECL(cancel_bonesfile); #endif @@ -638,6 +643,16 @@ #if defined(WIZARD) E void NDECL(read_wizkit); #endif +E void FDECL(paniclog, (const char *, const char *)); +E int FDECL(validate_prefix_locations, (char *)); +E char** NDECL(get_saved_games); +E void FDECL(free_saved_games, (char**)); +#ifdef SELF_RECOVER +E boolean NDECL(recover_savefile); +#endif +#ifdef HOLD_LOCKFILE_OPEN +E void NDECL(really_close); +#endif /* ### fountain.c ### */ @@ -662,11 +677,12 @@ E boolean FDECL(may_passwall, (XCHAR_P,XCHAR_P)); E boolean FDECL(bad_rock, (struct permonst *,XCHAR_P,XCHAR_P)); E boolean FDECL(invocation_pos, (XCHAR_P,XCHAR_P)); -E boolean FDECL(test_move, (int, int, int, int, BOOLEAN_P)); +E boolean FDECL(test_move, (int, int, int, int, int)); E void NDECL(domove); E void NDECL(invocation_message); E void FDECL(spoteffects, (BOOLEAN_P)); E char *FDECL(in_rooms, (XCHAR_P,XCHAR_P,int)); +E boolean FDECL(in_town, (int,int)); E void FDECL(check_special_room, (BOOLEAN_P)); E int NDECL(dopickup); E void NDECL(lookaround); @@ -695,6 +711,7 @@ E char *FDECL(upstart, (char *)); E char *FDECL(mungspaces, (char *)); E char *FDECL(eos, (char *)); +E char *FDECL(strkitten, (char *,CHAR_P)); E char *FDECL(s_suffix, (const char *)); E char *FDECL(xcrypt, (const char *,char *)); E boolean FDECL(onlyspace, (const char *)); @@ -790,6 +807,7 @@ E int FDECL(count_buc, (struct obj *,int)); E void FDECL(carry_obj_effects, (struct obj *)); E const char *FDECL(currency, (long)); +E void FDECL(silly_thing, (const char *,struct obj *)); /* ### ioctl.c ### */ @@ -905,6 +923,7 @@ E void FDECL(set_malign, (struct monst *)); E void FDECL(set_mimic_sym, (struct monst *)); E int FDECL(mbirth_limit, (int)); +E void FDECL(mimic_hit_msg, (struct monst *, SHORT_P)); #ifdef GOLDOBJ E void FDECL(mkmonmoney, (struct monst *, long)); #endif @@ -925,6 +944,7 @@ E int FDECL(noattacks, (struct permonst *)); E int FDECL(sleep_monst, (struct monst *,int,int)); E void FDECL(slept_monst, (struct monst *)); +E long FDECL(attk_protection, (int)); /* ### mhitu.c ### */ @@ -934,6 +954,7 @@ E void FDECL(expels, (struct monst *,struct permonst *,BOOLEAN_P)); E struct attack *FDECL(getmattk, (struct permonst *,int,int *,struct attack *)); E int FDECL(mattacku, (struct monst *)); +E int FDECL(magic_negation, (struct monst *)); E int FDECL(gazemu, (struct monst *,struct attack *)); E void FDECL(mdamageu, (struct monst *,int)); E int FDECL(could_seduce, (struct monst *,struct monst *,struct attack *)); @@ -943,7 +964,7 @@ /* ### minion.c ### */ -E void FDECL(msummon, (struct permonst *)); +E void FDECL(msummon, (struct monst *)); E void FDECL(summon_minion, (ALIGNTYP_P,BOOLEAN_P)); E int FDECL(demon_talk, (struct monst *)); E long FDECL(bribe, (struct monst *)); @@ -1107,7 +1128,7 @@ E void NDECL(restartcham); E void FDECL(restore_cham, (struct monst *)); E void FDECL(mon_animal_list, (BOOLEAN_P)); -E int FDECL(newcham, (struct monst *,struct permonst *,BOOLEAN_P)); +E int FDECL(newcham, (struct monst *,struct permonst *,BOOLEAN_P,BOOLEAN_P)); E int FDECL(can_be_hatched, (int)); E int FDECL(egg_type_from_parent, (int,BOOLEAN_P)); E boolean FDECL(dead_species, (int,BOOLEAN_P)); @@ -1128,10 +1149,12 @@ E boolean FDECL(can_blnd, (struct monst *,struct monst *,UCHAR_P,struct obj *)); E boolean FDECL(ranged_attk, (struct permonst *)); E boolean FDECL(hates_silver, (struct permonst *)); +E boolean FDECL(passes_bars, (struct permonst *)); E boolean FDECL(can_track, (struct permonst *)); E boolean FDECL(breakarm, (struct permonst *)); E boolean FDECL(sliparm, (struct permonst *)); E boolean FDECL(sticks, (struct permonst *)); +E int FDECL(num_horns, (struct permonst *)); /* E boolean FDECL(canseemon, (struct monst *)); */ E struct attack *FDECL(dmgtype_fromattack, (struct permonst *,int,int)); E boolean FDECL(dmgtype, (struct permonst *,int)); @@ -1145,6 +1168,8 @@ E int FDECL(big_to_little, (int)); E const char *FDECL(locomotion, (const struct permonst *,const char *)); E const char *FDECL(stagger, (const struct permonst *,const char *)); +E const char *FDECL(on_fire, (struct permonst *,struct attack *)); +E const struct permonst *FDECL(raceptr, (struct monst *)); /* ### monmove.c ### */ @@ -1176,7 +1201,7 @@ E void FDECL(create_mplayers, (int,BOOLEAN_P)); E void FDECL(mplayer_talk, (struct monst *)); -#ifdef MICRO +#if defined(MICRO) || defined(WIN32) /* ### msdos.c,os2.c,tos.c,winnt.c ### */ @@ -1225,8 +1250,7 @@ E int NDECL((*nt_kbhit)); E void FDECL(Delay, (int)); # endif /* WIN32 */ - -#endif /* MICRO */ +#endif /* MICRO || WIN32 */ /* ### mthrowu.c ### */ @@ -1240,6 +1264,7 @@ E struct obj *FDECL(m_carrying, (struct monst *,int)); E void FDECL(m_useup, (struct monst *,struct obj *)); E void FDECL(m_throw, (struct monst *,int,int,int,int,int,struct obj *)); +E boolean FDECL(hits_bars, (struct obj **,int,int,int,int)); /* ### muse.c ### */ @@ -1310,6 +1335,7 @@ E char *FDECL(simple_typename, (int)); E boolean FDECL(obj_is_pname, (struct obj *)); E char *FDECL(distant_name, (struct obj *,char *(*)(OBJ_P))); +E char *FDECL(fruitname, (BOOLEAN_P)); E char *FDECL(xname, (struct obj *)); E char *FDECL(mshot_xname, (struct obj *)); E boolean FDECL(the_unique_obj, (struct obj *obj)); @@ -1334,6 +1360,7 @@ E struct obj *FDECL(readobjnam, (char *,struct obj *,BOOLEAN_P)); E int FDECL(rnd_class, (int,int)); E const char *FDECL(cloak_simple_name, (struct obj *)); +E const char *FDECL(mimic_obj_name, (struct monst *)); /* ### options.c ### */ @@ -1352,7 +1379,7 @@ E char *FDECL(nh_getenv, (const char *)); E void FDECL(set_duplicate_opt_detection, (int)); E void FDECL(set_wc_option_mod_status, (unsigned long, int)); -E void FDECL(set_option_mod_status, (char *, int)); +E void FDECL(set_option_mod_status, (const char *,int)); /* ### pager.c ### */ @@ -1360,20 +1387,21 @@ E int NDECL(doquickwhatis); E int NDECL(doidtrap); E int NDECL(dowhatdoes); +E char *FDECL(dowhatdoes_core,(CHAR_P, char *)); E int NDECL(dohelp); E int NDECL(dohistory); /* ### pcmain.c ### */ -#if defined(MICRO) +#if defined(MICRO) || defined(WIN32) # ifdef CHDIR E void FDECL(chdirx, (char *,BOOLEAN_P)); # endif /* CHDIR */ -#endif /* MICRO */ +#endif /* MICRO || WIN32 */ /* ### pcsys.c ### */ -#ifdef MICRO +#if defined(MICRO) || defined(WIN32) E void NDECL(flushout); E int NDECL(dosh); # ifdef MFLOPPY @@ -1389,11 +1417,11 @@ E void VDECL(msmsg, (const char *,...)); # endif E FILE *FDECL(fopenp, (const char *,const char *)); -#endif /* MICRO */ +#endif /* MICRO || WIN32 */ /* ### pctty.c ### */ -#if defined(MICRO) +#if defined(MICRO) || defined(WIN32) E void NDECL(gettty); E void FDECL(settty, (const char *)); E void NDECL(setftty); @@ -1401,7 +1429,7 @@ #if defined(TIMED_DELAY) && defined(_MSC_VER) E void FDECL(msleep, (unsigned)); #endif -#endif /* MICRO */ +#endif /* MICRO || WIN32 */ /* ### pcunix.c ### */ @@ -1416,10 +1444,10 @@ #ifdef GOLDOBJ E int FDECL(collect_obj_classes, - (char *,struct obj *,BOOLEAN_P,boolean FDECL((*),(OBJ_P)))); + (char *,struct obj *,BOOLEAN_P,boolean FDECL((*),(OBJ_P)), int *)); #else E int FDECL(collect_obj_classes, - (char *,struct obj *,BOOLEAN_P,BOOLEAN_P,boolean FDECL((*),(OBJ_P)))); + (char *,struct obj *,BOOLEAN_P,BOOLEAN_P,boolean FDECL((*),(OBJ_P)), int *)); #endif E void FDECL(add_valid_menu_class, (int)); E boolean FDECL(allow_all, (struct obj *)); @@ -1619,14 +1647,14 @@ E NhRegion *FDECL(visible_region_at, (XCHAR_P,XCHAR_P)); E void FDECL(show_region, (NhRegion*, XCHAR_P, XCHAR_P)); E void FDECL(save_regions, (int,int)); -E void FDECL(rest_regions, (int)); +E void FDECL(rest_regions, (int,BOOLEAN_P)); E NhRegion* FDECL(create_gas_cloud, (XCHAR_P, XCHAR_P, int, int)); /* ### restore.c ### */ E void FDECL(inven_inuse, (BOOLEAN_P)); E int FDECL(dorecover, (int)); -E void NDECL(trickery); +E void FDECL(trickery, (char *)); E void FDECL(getlev, (int,int,XCHAR_P,BOOLEAN_P)); E void NDECL(minit); E boolean FDECL(lookup_id_mapping, (unsigned, unsigned *)); @@ -1741,7 +1769,7 @@ E void FDECL(hot_pursuit, (struct monst *)); E void FDECL(make_angry_shk, (struct monst *,XCHAR_P,XCHAR_P)); E int NDECL(dopay); -E boolean FDECL(paybill, (BOOLEAN_P)); +E boolean FDECL(paybill, (int)); E void NDECL(finish_paybill); E struct obj *FDECL(find_oid, (unsigned)); E long FDECL(contained_cost, (struct obj *,struct monst *,long,BOOLEAN_P, BOOLEAN_P)); @@ -1759,9 +1787,10 @@ E void FDECL(add_damage, (XCHAR_P,XCHAR_P,long)); E int FDECL(repair_damage, (struct monst *,struct damage *,BOOLEAN_P)); E int FDECL(shk_move, (struct monst *)); +E void FDECL(after_shk_move, (struct monst *)); E boolean FDECL(is_fshk, (struct monst *)); E void FDECL(shopdig, (int)); -E void FDECL(pay_for_damage, (const char *)); +E void FDECL(pay_for_damage, (const char *,BOOLEAN_P)); E boolean FDECL(costly_spot, (XCHAR_P,XCHAR_P)); E struct obj *FDECL(shop_object, (XCHAR_P,XCHAR_P)); E void FDECL(price_quote, (struct obj *)); @@ -1798,6 +1827,7 @@ E int NDECL(dotalk); #ifdef USER_SOUNDS E int FDECL(add_sound_mapping, (const char *)); +E void FDECL(play_sound_for_message, (const char *)); #endif /* ### sys/msdos/sound.c ### */ @@ -1843,7 +1873,7 @@ E long NDECL(somegold); #endif E void FDECL(stealgold, (struct monst *)); -E void FDECL(remove_worn_item, (struct obj *)); +E void FDECL(remove_worn_item, (struct obj *,BOOLEAN_P)); E int FDECL(steal, (struct monst *, char *)); E int FDECL(mpickobj, (struct monst *,struct obj *)); E void FDECL(stealamulet, (struct monst *)); @@ -1855,6 +1885,7 @@ /* ### steed.c ### */ #ifdef STEED +E void NDECL(rider_cant_reach); E boolean FDECL(can_saddle, (struct monst *)); E int FDECL(use_saddle, (struct obj *)); E boolean FDECL(can_ride, (struct monst *)); @@ -1868,10 +1899,11 @@ /* ### teleport.c ### */ -E boolean FDECL(goodpos, (int,int,struct monst *)); +E boolean FDECL(goodpos, (int,int,struct monst *,unsigned)); E boolean FDECL(enexto, (coord *,XCHAR_P,XCHAR_P,struct permonst *)); -E void FDECL(teleds, (int,int)); -E boolean NDECL(safe_teleds); +E boolean FDECL(enexto_core, (coord *,XCHAR_P,XCHAR_P,struct permonst *,unsigned)); +E void FDECL(teleds, (int,int,BOOLEAN_P)); +E boolean FDECL(safe_teleds, (BOOLEAN_P)); E boolean FDECL(teleport_pet, (struct monst *,BOOLEAN_P)); E void NDECL(tele); E int NDECL(dotele); @@ -1978,6 +2010,7 @@ E void FDECL(hurtmarmor,(struct monst *,int)); E boolean FDECL(attack_checks, (struct monst *,struct obj *)); +E void FDECL(check_caitiff, (struct monst *)); E schar FDECL(find_roll_to_hit, (struct monst *)); E boolean FDECL(attack, (struct monst *)); E boolean FDECL(hmon, (struct monst *,struct obj *,int)); @@ -2051,6 +2084,9 @@ const char *,BOOLEAN_P)); E unsigned long FDECL(get_feature_notice_ver, (char *)); E unsigned long NDECL(get_current_feature_ver); +#ifdef RUNTIME_PORT_ID +E void FDECL(append_port_id, (char *)); +#endif /* ### video.c ### */ @@ -2163,7 +2199,7 @@ E int FDECL(dmgval, (struct obj *,struct monst *)); E struct obj *FDECL(select_rwep, (struct monst *)); E struct obj *FDECL(select_hwep, (struct monst *)); -E void FDECL(possibly_unwield, (struct monst *)); +E void FDECL(possibly_unwield, (struct monst *,BOOLEAN_P)); E int FDECL(mon_wield_item, (struct monst *)); E int NDECL(abon); E int NDECL(dbon); @@ -2176,7 +2212,7 @@ E int NDECL(uwep_skill_type); E int FDECL(weapon_hit_bonus, (struct obj *)); E int FDECL(weapon_dam_bonus, (struct obj *)); -E void FDECL(skill_init, (struct def_skill *)); +E void FDECL(skill_init, (const struct def_skill *)); /* ### were.c ### */ @@ -2194,12 +2230,14 @@ E int NDECL(dowield); E int NDECL(doswapweapon); E int NDECL(dowieldquiver); -E int NDECL(dotwoweapon); +E boolean FDECL(wield_tool, (struct obj *,const char *)); E int NDECL(can_twoweapon); -E void NDECL(untwoweapon); +E void NDECL(drop_uswapwep); +E int NDECL(dotwoweapon); E void NDECL(uwepgone); E void NDECL(uswapwepgone); E void NDECL(uqwepgone); +E void NDECL(untwoweapon); E void FDECL(erode_obj, (struct obj *,BOOLEAN_P,BOOLEAN_P)); E int FDECL(chwepon, (struct obj *,int)); E int FDECL(welded, (struct obj *)); @@ -2251,13 +2289,15 @@ E void FDECL(setnotworn, (struct obj *)); E void FDECL(mon_set_minvis, (struct monst *)); E void FDECL(mon_adjust_speed, (struct monst *,int,struct obj *)); -E void FDECL(update_mon_intrinsics, (struct monst *,struct obj *,BOOLEAN_P)); +E void FDECL(update_mon_intrinsics, + (struct monst *,struct obj *,BOOLEAN_P,BOOLEAN_P)); E int FDECL(find_mac, (struct monst *)); E void FDECL(m_dowear, (struct monst *,BOOLEAN_P)); E struct obj *FDECL(which_armor, (struct monst *,long)); E void FDECL(mon_break_armor, (struct monst *,BOOLEAN_P)); E void FDECL(bypass_obj, (struct obj *)); E void NDECL(clear_bypasses); +E int FDECL(racial_exception, (struct monst *, struct obj *)); /* ### write.c ### */ @@ -2285,8 +2325,8 @@ E void FDECL(zapnodir, (struct obj *)); E int NDECL(dozap); E int FDECL(zapyourself, (struct obj *,BOOLEAN_P)); -E void FDECL(cancel_monst, (struct monst *,struct obj *, - BOOLEAN_P,BOOLEAN_P,BOOLEAN_P)); +E boolean FDECL(cancel_monst, (struct monst *,struct obj *, + BOOLEAN_P,BOOLEAN_P,BOOLEAN_P)); E void FDECL(weffects, (struct obj *)); E int NDECL(spell_damage_bonus); E const char *FDECL(exclam, (int force)); diff -Naurd ../nethack-3.4.0/include/flag.h ./include/flag.h --- ../nethack-3.4.0/include/flag.h Wed Mar 20 23:42:46 2002 +++ ./include/flag.h Mon Feb 24 15:25:05 2003 @@ -165,6 +165,8 @@ boolean window_inited; /* true if init_nhwindows() completed */ boolean vision_inited; /* true if vision is ready */ boolean menu_tab_sep; /* Use tabs to separate option menu fields */ + boolean menu_requested; /* Flag for overloaded use of 'm' prefix + * on some non-move commands */ int purge_monsters; /* # of dead monsters still on fmon list */ int *opt_booldup; /* for duplication of boolean opts in config file */ int *opt_compdup; /* for duplication of compound opts in config file */ @@ -174,7 +176,7 @@ boolean mon_polycontrol; /* debug: control monster polymorphs */ #endif #ifdef TTY_GRAPHICS - boolean prevmsg_window; /* show more old messages at a time */ + char prevmsg_window; /* type of old message window to use */ boolean extmenu; /* extended commands use menu interface */ #endif #ifdef MFLOPPY @@ -241,6 +243,7 @@ int wc_fontsiz_status; /* font size for the status window */ int wc_fontsiz_menu; /* font size for the menu window */ int wc_fontsiz_text; /* font size for text windows */ + int wc_scroll_amount; /* scroll this amount at scroll_margin */ int wc_scroll_margin; /* scroll map when this far from the edge */ int wc_map_mode; /* specify map viewing options, mostly @@ -249,9 +252,16 @@ boolean wc_splash_screen; /* display an opening splash screen or not */ boolean wc_popup_dialog; /* put queries in pop up dialogs instead of in the message window */ - boolean wc_large_font; /* draw in larger fonts (say, 12pt instead - of 9pt) */ boolean wc_eight_bit_input; /* allow eight bit input */ + boolean wc_mouse_support; /* allow mouse support */ + + boolean cmdassist; /* provide detailed assistance for some commands */ + boolean obsolete; /* obsolete options can point at this, it isn't used */ + /* Items which belong in flags, but are here to allow save compatibility */ + boolean lootabc; /* use "a/b/c" rather than "o/i/b" when looting */ + boolean showrace; /* show hero glyph by race rather than by role */ + boolean travelcmd; /* allow travel command */ + int runmode; /* update screen display during run moves */ }; /* @@ -266,7 +276,7 @@ #define hilite_pet wc_hilite_pet #define use_inverse wc_inverse #ifdef MAC_GRAPHICS_ENV -#define large_font wc_large_font +#define large_font obsolete #endif #ifdef MAC #define popup_dialog wc_popup_dialog @@ -276,4 +286,10 @@ extern NEARDATA struct flag flags; extern NEARDATA struct instance_flags iflags; +/* runmode options */ +#define RUN_TPORT 0 /* don't update display until movement stops */ +#define RUN_LEAP 1 /* update display every 7 steps */ +#define RUN_STEP 2 /* update display every single step */ +#define RUN_CRAWL 3 /* walk w/ extra delay after each update */ + #endif /* FLAG_H */ diff -Naurd ../nethack-3.4.0/include/global.h ./include/global.h --- ../nethack-3.4.0/include/global.h Wed Mar 20 23:42:47 2002 +++ ./include/global.h Mon Feb 24 15:25:05 2003 @@ -333,7 +339,7 @@ #define MAXULEV 30 /* max character experience level */ -#define MAXMONNO 120 /* geno monst after this number killed */ +#define MAXMONNO 120 /* extinct monst after this number created */ #define MHPMAX 500 /* maximum monster hp */ #endif /* GLOBAL_H */ diff -Naurd ../nethack-3.4.0/include/hack.h ./include/hack.h --- ../nethack-3.4.0/include/hack.h Wed Mar 20 23:42:47 2002 +++ ./include/hack.h Mon Feb 24 15:25:05 2003 @@ -24,11 +24,11 @@ /* symbolic names for capacity levels */ #define UNENCUMBERED 0 -#define SLT_ENCUMBER 1 -#define MOD_ENCUMBER 2 -#define HVY_ENCUMBER 3 -#define EXT_ENCUMBER 4 -#define OVERLOADED 5 +#define SLT_ENCUMBER 1 /* Burdened */ +#define MOD_ENCUMBER 2 /* Stressed */ +#define HVY_ENCUMBER 3 /* Strained */ +#define EXT_ENCUMBER 4 /* Overtaxed */ +#define OVERLOADED 5 /* Overloaded */ /* Macros for how a rumor was delivered in outrumor() */ #define BY_ORACLE 0 @@ -139,6 +139,7 @@ #define MM_ANGRY 0x10 /* monster is created angry */ #define MM_NONAME 0x20 /* monster is not christened */ #define MM_NOCOUNTBIRTH 0x40 /* don't increment born counter (for revival) */ +#define MM_IGNOREWATER 0x80 /* ignore water when positioning */ /* flags for special ggetobj status returns */ #define ALL_FINISHED 0x01 /* called routine already finished the job */ @@ -178,6 +179,11 @@ /* Flags to control dotrap() in trap.c */ #define NOWEBMSG 0x01 /* suppress stumble into web message */ +/* Flags to control test_move in hack.c */ +#define DO_MOVE 0 /* really doing the move */ +#define TEST_MOVE 1 /* test a normal move (move there next) */ +#define TEST_TRAV 2 /* test a future travel location */ + /*** some utility macros ***/ #define yn(query) yn_function(query,ynchars, 'n') #define ynq(query) yn_function(query,ynqchars, 'q') @@ -195,8 +201,9 @@ #define MAY_FRACTURE 0x10 /* boulders & statues may fracture */ /* Macros for launching objects */ -#define ROLL 1 -#define FLING 2 +#define ROLL 0x01 /* the object is rolling */ +#define FLING 0x02 /* the object is flying thru the air */ +#define LAUNCH_KNOWN 0x80 /* the hero caused this by explicit action */ /* Macros for explosion types */ #define EXPL_DARK 0 diff -Naurd ../nethack-3.4.0/include/mfndpos.h ./include/mfndpos.h --- ../nethack-3.4.0/include/mfndpos.h Wed Mar 20 23:42:49 2002 +++ ./include/mfndpos.h Mon Feb 24 15:25:05 2003 @@ -17,6 +17,7 @@ #define ALLOW_ROCK 0x02000000L /* pushes rocks */ #define ALLOW_WALL 0x04000000L /* walks thru walls */ #define ALLOW_DIG 0x08000000L /* digs */ +#define ALLOW_BARS 0x10000000L /* may pass thru iron bars */ #define ALLOW_SANCT 0x20000000L /* enters temples */ #define ALLOW_SSM 0x40000000L /* ignores scare monster */ #ifdef NHSTDC diff -Naurd ../nethack-3.4.0/include/mkroom.h ./include/mkroom.h --- ../nethack-3.4.0/include/mkroom.h Wed Mar 20 23:42:49 2002 +++ ./include/mkroom.h Mon Feb 24 15:25:05 2003 @@ -31,7 +31,7 @@ int iprob; /* probability of an item type */ int itype; /* item type: if >=0 a class, if < 0 a specific item */ } iprobs[5]; - const char **shknms; /* list of shopkeeper names for this type */ + const char * const *shknms; /* list of shopkeeper names for this type */ }; extern NEARDATA struct mkroom rooms[(MAXNROFROOMS+1)*2]; diff -Naurd ../nethack-3.4.0/include/monattk.h ./include/monattk.h --- ../nethack-3.4.0/include/monattk.h Wed Mar 20 23:42:49 2002 +++ ./include/monattk.h Mon Feb 24 15:25:05 2003 @@ -8,6 +8,7 @@ /* Add new attack types below - ordering affects experience (exper.c). * Attacks > AT_BUTT are worth extra experience. */ +#define AT_ANY (-1) /* fake attack; dmgtype_fromattack wildcard */ #define AT_NONE 0 /* passive monster (ex. acid blob) */ #define AT_CLAW 1 /* claw (punch, hit, etc.) */ #define AT_BITE 2 /* bite */ @@ -32,6 +33,7 @@ * Note that 1-10 correspond to the types of attack used in buzz(). * Please don't disturb the order unless you rewrite the buzz() code. */ +#define AD_ANY (-1) /* fake damage; attacktype_fordmg wildcard */ #define AD_PHYS 0 /* ordinary physical */ #define AD_MAGM 1 /* magic missiles */ #define AD_FIRE 2 /* fire damage */ diff -Naurd ../nethack-3.4.0/include/mondata.h ./include/mondata.h --- ../nethack-3.4.0/include/mondata.h Wed Mar 20 23:42:49 2002 +++ ./include/mondata.h Mon Feb 24 15:25:05 2003 @@ -19,6 +19,11 @@ #define resists_acid(mon) (((mon)->mintrinsics & MR_ACID) != 0) #define resists_ston(mon) (((mon)->mintrinsics & MR_STONE) != 0) +#define is_lminion(mon) (is_minion((mon)->data) && \ + (mon)->data->maligntyp >= A_COALIGNED && \ + ((mon)->data != &mons[PM_ANGEL] || \ + EPRI(mon)->shralign > 0)) + #define is_flyer(ptr) (((ptr)->mflags1 & M1_FLY) != 0L) #define is_floater(ptr) ((ptr)->mlet == S_EYE) #define is_clinger(ptr) (((ptr)->mflags1 & M1_CLING) != 0L) @@ -40,6 +45,7 @@ #define nolimbs(ptr) (((ptr)->mflags1 & M1_NOLIMBS) == M1_NOLIMBS) #define notake(ptr) (((ptr)->mflags1 & M1_NOTAKE) != 0L) #define has_head(ptr) (((ptr)->mflags1 & M1_NOHEAD) == 0L) +#define has_horns(ptr) (num_horns(ptr) > 0) #define is_whirly(ptr) ((ptr)->mlet == S_VORTEX || \ (ptr) == &mons[PM_AIR_ELEMENTAL]) #define is_silent(ptr) ((ptr)->msound == MS_SILENT) @@ -105,8 +111,6 @@ #define is_dlord(ptr) (is_demon(ptr) && is_lord(ptr)) #define is_dprince(ptr) (is_demon(ptr) && is_prince(ptr)) #define is_minion(ptr) ((ptr)->mflags2 & M2_MINION) -#define is_lminion(ptr) (is_minion(ptr) && \ - (ptr)->maligntyp >= A_COALIGNED) #define likes_gold(ptr) (((ptr)->mflags2 & M2_GREEDY) != 0L) #define likes_gems(ptr) (((ptr)->mflags2 & M2_JEWELS) != 0L) #define likes_objs(ptr) (((ptr)->mflags2 & M2_COLLECT) != 0L || \ diff -Naurd ../nethack-3.4.0/include/monst.h ./include/monst.h --- ../nethack-3.4.0/include/monst.h Wed Mar 20 23:42:50 2002 +++ ./include/monst.h Mon Feb 24 15:25:05 2003 @@ -6,7 +6,7 @@ #define MONST_H /* The weapon_check flag is used two ways: - * 1) When calling mon_wield_item, is 2, 3, or 4 depending on what is desired. + * 1) When calling mon_wield_item, is 2-6 depending on what is desired. * 2) Between calls to mon_wield_item, is 0 or 1 depending on whether or not * the weapon is known by the monster to be cursed (so it shouldn't bother * trying for another weapon). @@ -20,6 +20,8 @@ # define NEED_RANGED_WEAPON 2 # define NEED_HTH_WEAPON 3 # define NEED_PICK_AXE 4 +# define NEED_AXE 5 +# define NEED_PICK_OR_AXE 6 /* The following flags are used for the second argument to display_minventory * in invent.c: @@ -98,7 +100,7 @@ Bitfield(mstun,1); /* stunned (off balance) */ Bitfield(mconf,1); /* confused */ Bitfield(mpeaceful,1); /* does not attack unprovoked */ - Bitfield(mtrapped,1); /* trapped in a pit or bear trap */ + Bitfield(mtrapped,1); /* trapped in a pit, web or bear trap */ Bitfield(mleashed,1); /* monster is on a leash */ Bitfield(isshk,1); /* is shopkeeper */ Bitfield(isminion,1); /* is a minion */ diff -Naurd ../nethack-3.4.0/include/obj.h ./include/obj.h --- ../nethack-3.4.0/include/obj.h Wed Mar 20 23:42:51 2002 +++ ./include/obj.h Mon Feb 24 15:25:05 2003 @@ -70,6 +70,7 @@ Bitfield(olocked,1); /* object is locked */ Bitfield(obroken,1); /* lock has been broken */ Bitfield(otrapped,1); /* container is trapped */ + /* or accidental tripped rolling boulder trap */ #define opoisoned otrapped /* object (weapon) is coated with poison */ Bitfield(recharged,3); /* number of times it's been recharged */ @@ -179,7 +180,24 @@ objects[otmp->otyp].oc_armcat == ARM_SHIRT) #define is_suit(otmp) (otmp->oclass == ARMOR_CLASS && \ objects[otmp->otyp].oc_armcat == ARM_SUIT) +#define is_elven_armor(otmp) ((otmp)->otyp == ELVEN_LEATHER_HELM\ + || (otmp)->otyp == ELVEN_MITHRIL_COAT\ + || (otmp)->otyp == ELVEN_CLOAK\ + || (otmp)->otyp == ELVEN_SHIELD\ + || (otmp)->otyp == ELVEN_BOOTS) +#define is_orcish_armor(otmp) ((otmp)->otyp == ORCISH_HELM\ + || (otmp)->otyp == ORCISH_CHAIN_MAIL\ + || (otmp)->otyp == ORCISH_RING_MAIL\ + || (otmp)->otyp == ORCISH_CLOAK\ + || (otmp)->otyp == URUK_HAI_SHIELD\ + || (otmp)->otyp == ORCISH_SHIELD) +#define is_dwarvish_armor(otmp) ((otmp)->otyp == DWARVISH_IRON_HELM\ + || (otmp)->otyp == DWARVISH_MITHRIL_COAT\ + || (otmp)->otyp == DWARVISH_CLOAK\ + || (otmp)->otyp == DWARVISH_ROUNDSHIELD) +#define is_gnomish_armor(otmp) (FALSE) + /* Eggs and other food */ #define MAX_EGG_HATCH_TIME 200 /* longest an egg can remain unhatched */ #define stale_egg(egg) ((monstermoves - (egg)->age) > (2*MAX_EGG_HATCH_TIME)) @@ -211,6 +229,32 @@ - GRAY_DRAGON_SCALE_MAIL] #define Dragon_to_scales(pm) (GRAY_DRAGON_SCALES + (pm - mons)) +/* Elven gear */ +#define is_elven_weapon(otmp) ((otmp)->otyp == ELVEN_ARROW\ + || (otmp)->otyp == ELVEN_SPEAR\ + || (otmp)->otyp == ELVEN_DAGGER\ + || (otmp)->otyp == ELVEN_SHORT_SWORD\ + || (otmp)->otyp == ELVEN_BROADSWORD\ + || (otmp)->otyp == ELVEN_BOW) +#define is_elven_obj(otmp) (is_elven_armor(otmp) || is_elven_weapon(otmp)) + +/* Orcish gear */ +#define is_orcish_obj(otmp) (is_orcish_armor(otmp)\ + || (otmp)->otyp == ORCISH_ARROW\ + || (otmp)->otyp == ORCISH_SPEAR\ + || (otmp)->otyp == ORCISH_DAGGER\ + || (otmp)->otyp == ORCISH_SHORT_SWORD\ + || (otmp)->otyp == ORCISH_BOW) + +/* Dwarvish gear */ +#define is_dwarvish_obj(otmp) (is_dwarvish_armor(otmp)\ + || (otmp)->otyp == DWARVISH_SPEAR\ + || (otmp)->otyp == DWARVISH_SHORT_SWORD\ + || (otmp)->otyp == DWARVISH_MATTOCK) + +/* Gnomish gear */ +#define is_gnomish_obj(otmp) (is_gnomish_armor(otmp)) + /* Light sources */ #define Is_candle(otmp) (otmp->otyp == TALLOW_CANDLE || \ otmp->otyp == WAX_CANDLE) diff -Naurd ../nethack-3.4.0/include/objclass.h ./include/objclass.h --- ../nethack-3.4.0/include/objclass.h Wed Mar 20 23:42:51 2002 +++ ./include/objclass.h Mon Feb 24 15:25:05 2003 @@ -133,7 +133,7 @@ #define SCROLL_CLASS 9 #define SPBOOK_CLASS 10 /* actually SPELL-book */ #define WAND_CLASS 11 -#define GOLD_CLASS 12 +#define COIN_CLASS 12 #define GEM_CLASS 13 #define ROCK_CLASS 14 #define BALL_CLASS 15 diff -Naurd ../nethack-3.4.0/include/pcconf.h ./include/pcconf.h --- ../nethack-3.4.0/include/pcconf.h Wed Mar 20 23:42:51 2002 +++ ./include/pcconf.h Mon Feb 24 15:25:05 2003 @@ -17,7 +17,7 @@ * _MSC_VER is defined automatically by Microsoft C. * __BORLANDC__ is defined automatically by Borland C. * __SC__ is defined automatically by Symantec C. - * Note: 3.4.0 was not verified with Symantec C. + * Note: 3.4.1 was not verified with Symantec C. */ /* @@ -99,10 +99,6 @@ /* amiconf.h). In the future this will be the */ /* hook for mail reader implementation. */ -/*# define PC_LOCKING */ /* Allow confirmation before overwriting game */ - /* that is in progress or aborted when another */ - /* game is started with the same player name. */ - /* The following is needed for prototypes of certain functions */ #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__SC__) @@ -141,7 +137,7 @@ # endif #define NOCWD_ASSUMPTIONS /* Allow paths to be specified for HACKDIR, LEVELDIR, SAVEDIR, BONESDIR, DATADIR, - SCOREDIR, LOCKDIR, and CONFIGDIR */ + SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR. */ #endif /* MSDOS configuration stuff */ @@ -160,12 +156,16 @@ #include "system.h" #endif -#ifdef __GO32__ +#ifdef __DJGPP__ #include /* close(), etc. */ -/* setmode is in io.h but lock() in io.h interferes with lock[] in decl.h */ -extern int FDECL(setmode, (int,int)); +/* lock() in io.h interferes with lock[] in decl.h */ +#define lock djlock +#include +#undef lock #include /* kbhit() */ #define PC_LOCKING +#define HOLD_LOCKFILE_OPEN +#define SELF_RECOVER /* NetHack itself can recover games */ #endif # ifdef MSDOS diff -Naurd ../nethack-3.4.0/include/qtext.h ./include/qtext.h --- ../nethack-3.4.0/include/qtext.h Wed Mar 20 23:42:52 2002 +++ ./include/qtext.h Mon Feb 24 15:25:05 2003 @@ -35,6 +35,7 @@ #define CREC_IN_MSG "Control record encountered during message - line %d\n" #define DUP_MSG "Duplicate message number at line %d\n" #define END_NOT_IN_MSG "End record encountered before message - line %d\n" +#define TEXT_NOT_IN_MSG "Text encountered outside message - line %d\n" #define UNREC_CREC "Unrecognized Control record at line %d\n" #define OUT_OF_HEADERS "Too many message types (line %d)\nAdjust N_HDR in qtext.h and recompile.\n" #define OUT_OF_MESSAGES "Too many messages in class (line %d)\nAdjust N_MSG in qtext.h and recompile.\n" @@ -105,6 +106,7 @@ #define QT_DEMONIC 30 #define QTN_DEMONIC 20 +#define QT_BANISHED 60 #endif /***** !MAKEDEFS *****/ #endif /* QTEXT_H */ diff -Naurd ../nethack-3.4.0/include/region.h ./include/region.h --- ../nethack-3.4.0/include/region.h Wed Mar 20 23:42:54 2002 +++ ./include/region.h Mon Feb 24 15:25:05 2003 @@ -9,6 +9,27 @@ typedef boolean FDECL((*callback_proc), (genericptr_t, genericptr_t)); +/* + * Overload the old player_inside field with two values, coded in such + * a way as to retain compatibility with 3.4.0 save and bones files; + * this relies on the fact that nethack's `boolean' is really stored + * in a `char' (or bigger type) rather than in a single bit. + * + * 3.4.1 save and bones files will be correct. + * 3.4.0 save files restored under 3.4.1 will be correct. + * 3.4.0 bones files used with 3.4.1 will continue to have the minor + * 3.4.0 bug of falsely claiming that the current game's hero is + * responsible for the dead former hero's stinking clouds. + */ +#define REG_HERO_INSIDE 1 +#define REG_NOT_HEROS 2 +#define hero_inside(r) ((unsigned)(r)->player_flags & REG_HERO_INSIDE) +#define heros_fault(r) (!((unsigned)(r)->player_flags & REG_NOT_HEROS)) +#define set_hero_inside(r) ((r)->player_flags |= REG_HERO_INSIDE) +#define clear_hero_inside(r) ((r)->player_flags &= ~REG_HERO_INSIDE) +#define set_heros_fault(r) ((r)->player_flags &= ~REG_NOT_HEROS) +#define clear_heros_fault(r) ((r)->player_flags |= REG_NOT_HEROS) + typedef struct { NhRect bounding_box; /* Bounding box of the region */ NhRect *rects; /* Rectangles composing the region */ @@ -28,7 +49,7 @@ short leave_f; /* Function to call when the player leaves */ short inside_f; /* Function to call every turn if player's inside */ - boolean player_inside; /* Is the player inside this region */ + boolean player_flags; /* (see above) */ unsigned int* monsters; /* Monsters currently inside this region */ short n_monst; /* Number of monsters inside this region */ short max_monst; /* Maximum number of monsters that can be diff -Naurd ../nethack-3.4.0/include/rm.h ./include/rm.h --- ../nethack-3.4.0/include/rm.h Wed Mar 20 23:42:54 2002 +++ ./include/rm.h Mon Feb 24 15:25:05 2003 @@ -267,6 +267,12 @@ */ #define F_LOOTED 1 #define F_WARNED 2 +#define FOUNTAIN_IS_WARNED(x,y) (levl[x][y].looted & F_WARNED) +#define FOUNTAIN_IS_LOOTED(x,y) (levl[x][y].looted & F_LOOTED) +#define SET_FOUNTAIN_WARNED(x,y) levl[x][y].looted |= F_WARNED; +#define SET_FOUNTAIN_LOOTED(x,y) levl[x][y].looted |= F_LOOTED; +#define CLEAR_FOUNTAIN_WARNED(x,y) levl[x][y].looted &= ~F_WARNED; +#define CLEAR_FOUNTAIN_LOOTED(x,y) levl[x][y].looted &= ~F_LOOTED; /* * Doors are even worse :-) The special warning has a side effect diff -Naurd ../nethack-3.4.0/include/wceconf.h ./include/wceconf.h --- ../nethack-3.4.0/include/wceconf.h Thu Jan 1 01:00:00 1970 +++ ./include/wceconf.h Mon Feb 24 15:25:05 2003 @@ -0,0 +1,319 @@ +/* Copyright (C) 2001 by Alex Kompel */ +/* Copyright (c) NetHack PC Development Team 1993, 1994. */ +/* NetHack may be freely redistributed. See license for details. */ + +#ifndef WCECONF_H +#define WCECONF_H + +#pragma warning(disable:4142) /* benign redefinition of type */ + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include + +/* Detect the targe device */ +#if defined(WIN32_PLATFORM_PSPC) +# if _WIN32_WCE >= 300 +# define WIN_CE_POCKETPC +# else +# define WIN_CE_PS2xx +# endif +#elif defined(WIN32_PLATFORM_HPCPRO) +# define WIN_CE_HPCPRO +#elif defined(WIN32_PLATFORM_WFSP) +# define WIN_CE_SMARTPHONE +#else +# error "Unsupported Windows CE platform" +#endif + +/* #define SHELL /* nt use of pcsys routines caused a hang */ + +#define RANDOM /* have Berkeley random(3) */ +#define TEXTCOLOR /* Color text */ + +#define EXEPATH /* Allow .exe location to be used as HACKDIR */ +#define TRADITIONAL_GLYPHMAP /* Store glyph mappings at level change time */ + +#define PC_LOCKING /* Prevent overwrites of aborted or in-progress games */ + /* without first receiving confirmation. */ + +#define SELF_RECOVER /* Allow the game itself to recover from an aborted game */ + +#define NOTSTDC /* no strerror() */ + +#define USER_SOUNDS + +/* + * ----------------------------------------------------------------- + * The remaining code shouldn't need modification. + * ----------------------------------------------------------------- + */ +/* #define SHORT_FILENAMES /* All NT filesystems support long names now */ + +#ifdef MICRO +#undef MICRO /* never define this! */ +#endif + +#define NOCWD_ASSUMPTIONS /* Always define this. There are assumptions that + it is defined for WIN32. + Allow paths to be specified for HACKDIR, + LEVELDIR, SAVEDIR, BONESDIR, DATADIR, + SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */ +#define NO_TERMS +#define ASCIIGRAPH + +#ifdef OPTIONS_USED +#undef OPTIONS_USED +#endif +#ifdef MSWIN_GRAPHICS +#define OPTIONS_USED "guioptions" +#else +#define OPTIONS_USED "ttyoptions" +#endif +#define OPTIONS_FILE OPTIONS_USED + +#define PORT_HELP "porthelp" + +#if defined(WIN_CE_POCKETPC) +# define PORT_CE_PLATFORM "Pocket PC" +#elif defined(WIN_CE_PS2xx) +# define PORT_CE_PLATFORM "Palm-size PC 2.11" +#elif defined(WIN_CE_HPCPRO) +# define PORT_CE_PLATFORM "H/PC Pro 2.11" +#elif defined(WIN_CE_SMARTPHONE) +# define PORT_CE_PLATFORM "Smartphone 2002" +#endif + +#if defined(ARM) +# define PORT_CE_CPU "ARM" +#elif defined(PPC) +# define PORT_CE_CPU "PPC" +#elif defined(ALPHA) +# define PORT_CE_CPU "ALPHA" +#elif defined(SH3) +# define PORT_CE_CPU "SH3" +#elif defined(SH4) +# define PORT_CE_CPU "SH4" +#elif defined(MIPS) +# define PORT_CE_CPU "MIPS" +#elif defined(X86) || defined(_X86_) +# define PORT_CE_CPU "X86" +#else +# error Only ARM, PPC, ALPHA, SH3, SH4, MIPS and X86 supported +#endif + +#define RUNTIME_PORT_ID /* trigger run-time port identification since + Makedefs is bootstrapped on a cross-platform. */ + +#include /* Provides prototypes of strncmpi(), etc. */ +#ifdef STRNCMPI +#define strncmpi(a,b,c) _strnicmp(a,b,c) +#endif + +#ifdef STRCMPI +#define strcmpi(a,b) _stricmp(a,b) +#define stricmp(a,b) _stricmp(a,b) +#endif + +#include + +#define PATHLEN BUFSZ /* maximum pathlength */ +#define FILENAME BUFSZ /* maximum filename length (conservative) */ + +#if defined(_MAX_PATH) && defined(_MAX_FNAME) +# if (_MAX_PATH < BUFSZ) && (_MAX_FNAME < BUFSZ) +#undef PATHLEN +#undef FILENAME +#define PATHLEN _MAX_PATH +#define FILENAME _MAX_FNAME +# endif +#endif + + +#define NO_SIGNAL +#define index strchr +#define rindex strrchr +#define USE_STDARG +#ifdef RANDOM +/* Use the high quality random number routines. */ +#define Rand() random() +#else +#define Rand() rand() +#endif + +#define FCMASK 0660 /* file creation mask */ +#define regularize nt_regularize +#define HLOCK "NHPERM" + +#ifndef M +#define M(c) ((char) (0x80 | (c))) +/* #define M(c) ((c) - 128) */ +#endif + +#ifndef C +#define C(c) (0x1f & (c)) +#endif + +#if defined(DLB) +#define FILENAME_CMP _stricmp /* case insensitive */ +#endif + +#if 0 +extern char levels[], bones[], permbones[], +#endif /* 0 */ + +/* this was part of the MICRO stuff in the past */ +extern const char *alllevels, *allbones; +extern char hackdir[]; +#define ABORT C('a') +#define getuid() 1 +#define getlogin() ((char *)0) +extern void NDECL(win32_abort); +#ifdef WIN32CON +extern void FDECL(nttty_preference_update, (const char *)); +extern void NDECL(toggle_mouse_support); +#endif + +#ifndef alloca +#define ALLOCA_HACK /* used in util/panic.c */ +#endif + +#ifndef REDO +#undef Getchar +#define Getchar nhgetch +#endif + +#ifdef _MSC_VER +#if 0 +#pragma warning(disable:4018) /* signed/unsigned mismatch */ +#pragma warning(disable:4305) /* init, conv from 'const int' to 'char' */ +#endif +#pragma warning(disable:4761) /* integral size mismatch in arg; conv supp*/ +#ifdef YYPREFIX +#pragma warning(disable:4102) /* unreferenced label */ +#endif +#endif + +/* UNICODE stuff */ +#define NHSTR_BUFSIZE 255 +#ifdef UNICODE + #define NH_W2A(w, a, cb) ( WideCharToMultiByte( \ + CP_ACP, \ + 0, \ + (w), \ + -1, \ + (a), \ + (cb), \ + NULL, \ + NULL), (a) ) + + #define NH_A2W(a, w, cb) ( MultiByteToWideChar( \ + CP_ACP, \ + 0, \ + (a), \ + -1, \ + (w), \ + (cb)), (w) ) +#else + #define NH_W2A(w, a, cb) (strncpy((a), (w), (cb))) + + #define NH_A2W(a, w, cb) (strncpy((w), (a), (cb))) +#endif + +extern int FDECL(set_win32_option, (const char *, const char *)); + +/* Missing definitions */ +extern int mswin_have_input(); +#define kbhit mswin_have_input + +#define getenv(a) ((char*)NULL) + +/* __stdio.h__ */ +#define perror(a) +#define freopen(a, b, c) fopen(a, b) +extern int isatty(int); + +/* __time.h___ */ +#ifndef _TIME_T_DEFINED +typedef __int64 time_t; /* time value */ +#define _TIME_T_DEFINED /* avoid multiple def's of time_t */ +#endif + +#ifndef _TM_DEFINED +struct tm { + int tm_sec; /* seconds after the minute - [0,59] */ + int tm_min; /* minutes after the hour - [0,59] */ + int tm_hour; /* hours since midnight - [0,23] */ + int tm_mday; /* day of the month - [1,31] */ + int tm_mon; /* months since January - [0,11] */ + int tm_year; /* years since 1900 */ + int tm_wday; /* days since Sunday - [0,6] */ + int tm_yday; /* days since January 1 - [0,365] */ + int tm_isdst; /* daylight savings time flag - - NOT IMPLEMENTED */ + }; +#define _TM_DEFINED +#endif + +struct tm * __cdecl localtime(const time_t *); +time_t __cdecl time(time_t *); + +/* __stdio.h__ */ +#ifndef BUFSIZ +#define BUFSIZ 255 +#endif + +#define rewind(stream) (void)fseek( stream, 0L, SEEK_SET ) + +/* __io.h__ */ +typedef long off_t; + +int __cdecl close(int); +int __cdecl creat(const char *, int); +int __cdecl eof(int); +long __cdecl lseek(int, long, int); +int __cdecl open(const char *, int, ...); +int __cdecl read(int, void *, unsigned int); +int __cdecl unlink(const char *); +int __cdecl write(int, const void *, unsigned int); +int __cdecl rename(const char *, const char *); +int __cdecl access(const char *, int); + +#ifdef DeleteFile +#undef DeleteFile +#endif +#define DeleteFile(a) unlink(a) + +int chdir( const char *dirname ); +char *getcwd( char *buffer, int maxlen ); + +/* __stdlib.h__ */ +#define abort() (void)TerminateProcess(GetCurrentProcess(), 0) +#ifndef strdup +#define strdup _strdup +#endif + +/* sys/stat.h */ +#define S_IWRITE GENERIC_WRITE +#define S_IREAD GENERIC_READ + + +/* CE 2.xx is missing even more stuff */ +#if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) +#define ZeroMemory(p, s) memset((p), 0, (s)) + +int __cdecl isupper(int c); +int __cdecl isdigit(int c); +int __cdecl isspace(int c); +int __cdecl isprint(int c); + +char* __cdecl _strdup(const char* s); +char* __cdecl strrchr( const char *string, int c ); +int __cdecl _stricmp(const char* a, const char* b); +#endif + +/* ARM - the processor; avoids conflict with ARM in hack.h */ +# ifdef ARM +# undef ARM +# endif + +#endif /* WCECONF_H */ diff -Naurd ../nethack-3.4.0/include/winprocs.h ./include/winprocs.h --- ../nethack-3.4.0/include/winprocs.h Wed Mar 20 23:42:58 2002 +++ ./include/winprocs.h Mon Feb 24 15:25:05 2003 @@ -157,15 +157,16 @@ #define WC_FONTSIZ_MENU 0x100000L /* 21 supports specification of mnu win font */ #define WC_FONTSIZ_TEXT 0x200000L /* 22 supports specification of txt win font */ #define WC_SCROLL_MARGIN 0x400000L /* 23 supports setting scroll margin for map */ -#define WC_SPLASH_SCREEN 0x800000L /* 24 supports setting scroll margin for map */ +#define WC_SPLASH_SCREEN 0x800000L /* 24 supports display of splash screen */ #define WC_POPUP_DIALOG 0x1000000L /* 25 supports queries in pop dialogs */ -#define WC_LARGE_FONT 0x2000000L /* 26 Port supports large font */ +#define WC_SCROLL_AMOUNT 0x2000000L /* 26 scroll this amount at scroll margin */ #define WC_EIGHT_BIT_IN 0x4000000L /* 27 8-bit character input */ #define WC_PERM_INVENT 0x8000000L /* 28 8-bit character input */ #define WC_MAP_MODE 0x10000000L /* 29 map_mode option */ #define WC_WINDOWCOLORS 0x20000000L /* 30 background color for message window */ #define WC_PLAYER_SELECTION 0x40000000L /* 31 background color for message window */ - /* 1 free bit */ +#define WC_MOUSE_SUPPORT 0x80000000L /* 32 mouse support */ + /* no free bits */ #define ALIGN_LEFT 1 #define ALIGN_RIGHT 2 @@ -201,7 +202,7 @@ #endif struct wc_Opt { - char *wc_name; + const char *wc_name; unsigned long wc_bit; }; diff -Naurd ../nethack-3.4.0/src/allmain.c ./src/allmain.c --- ../nethack-3.4.0/src/allmain.c Wed Mar 20 23:42:59 2002 +++ ./src/allmain.c Mon Feb 24 15:25:05 2003 @@ -100,7 +100,7 @@ /* calculate how much time passed. */ #ifdef STEED - if (u.usteed && flags.mv) { + if (u.usteed && u.umoved) { /* your speed doesn't augment steed's speed */ moveamt = mcalcmove(u.usteed); } else @@ -221,21 +221,27 @@ if(!u.uinvulnerable) { if(Teleportation && !rn2(85)) { -#ifdef REDO xchar old_ux = u.ux, old_uy = u.uy; -#endif tele(); -#ifdef REDO if (u.ux != old_ux || u.uy != old_uy) { + if (!next_to_u()) { + check_leash(old_ux, old_uy); + } +#ifdef REDO /* clear doagain keystrokes */ pushch(0); savech(0); - } #endif + } } + /* delayed change may not be valid anymore */ + if ((change == 1 && !Polymorph) || + (change == 2 && u.ulycn == NON_PM)) + change = 0; if(Polymorph && !rn2(100)) change = 1; - else if (u.ulycn >= LOW_PM && !rn2(80 - (20 * night()))) + else if (u.ulycn >= LOW_PM && !Upolyd && + !rn2(80 - (20 * night()))) change = 2; if (change && !Unchanging) { if (multi >= 0) { @@ -278,10 +284,13 @@ /* when immobile, count is in turns */ if(multi < 0) { - if (++multi == 0) /* finished yet? */ + if (++multi == 0) { /* finished yet? */ unmul((char *)0); + /* if unmul caused a level change, take it now */ + if (u.utotype) deferred_goto(); + } } - } + } } while (youmonst.movement 0) makeknown(MAGIC_WHISTLE); + if (pet_cnt > 0) makeknown(obj->otyp); } } @@ -398,7 +400,7 @@ use_leash(obj) struct obj *obj; { - register int x, y; + coord cc; register struct monst *mtmp; int spotmon; @@ -407,12 +409,9 @@ return; } - if(!getdir((char *)0)) return; - - x = u.ux + u.dx; - y = u.uy + u.dy; + if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return; - if((x == u.ux) && (y == u.uy)) { + if((cc.x == u.ux) && (cc.y == u.uy)) { #ifdef STEED if (u.usteed && u.dz > 0) { mtmp = u.usteed; @@ -424,7 +423,7 @@ return; } - if(!(mtmp = m_at(x, y))) { + if(!(mtmp = m_at(cc.x, cc.y))) { There("is no creature there."); return; } @@ -528,94 +527,65 @@ register xchar x, y; { register struct obj *otmp; - register struct monst *mtmp = fmon; + register struct monst *mtmp; - for(otmp = invent; otmp; otmp = otmp->nobj) - if(otmp->otyp == LEASH && otmp->leashmon != 0) { - while(mtmp) { - if(!DEADMONSTER(mtmp) && ((int)mtmp->m_id == otmp->leashmon && - (dist2(u.ux,u.uy,mtmp->mx,mtmp->my) > - dist2(x,y,mtmp->mx,mtmp->my))) - ) { - if(otmp->cursed && !breathless(mtmp->data)) { - if(um_dist(mtmp->mx, mtmp->my, 5)) { - pline("%s chokes to death!",Monnam(mtmp)); - mondied(mtmp); - } else - if(um_dist(mtmp->mx, mtmp->my, 3)) - pline("%s chokes on the leash!", - Monnam(mtmp)); - } else { - if(um_dist(mtmp->mx, mtmp->my, 5)) { - pline("%s leash snaps loose!", - s_suffix(Monnam(mtmp))); - m_unleash(mtmp, FALSE); - } else { - if(um_dist(mtmp->mx, mtmp->my, 3)) { - You("pull on the leash."); - if (mtmp->data->msound != MS_SILENT) - switch(rn2(3)) { - case 0: growl(mtmp); break; - case 1: yelp(mtmp); break; - default: whimper(mtmp); break; - } - } + for (otmp = invent; otmp; otmp = otmp->nobj) { + if (otmp->otyp != LEASH || otmp->leashmon == 0) continue; + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if ((int)mtmp->m_id == otmp->leashmon) break; + } + if (!mtmp) { + impossible("leash in use isn't attached to anything?"); + otmp->leashmon = 0; + continue; + } + if (dist2(u.ux,u.uy,mtmp->mx,mtmp->my) > + dist2(x,y,mtmp->mx,mtmp->my)) { + if (!um_dist(mtmp->mx, mtmp->my, 3)) { + ; /* still close enough */ + } else if (otmp->cursed && !breathless(mtmp->data)) { + if (um_dist(mtmp->mx, mtmp->my, 5) || + (mtmp->mhp -= rnd(2)) <= 0) { + long save_pacifism = u.uconduct.killer; + + Your("leash chokes %s to death!", mon_nam(mtmp)); + /* hero might not have intended to kill pet, but + that's the result of his actions; gain experience, + lose pacifism, take alignment and luck hit, make + corpse less likely to remain tame after revival */ + xkilled(mtmp, 0); /* no "you kill it" message */ + /* life-saving doesn't ordinarily reset this */ + if (mtmp->mhp > 0) u.uconduct.killer = save_pacifism; + } else { + pline("%s chokes on the leash!", Monnam(mtmp)); + /* tameness eventually drops to 1 here (never 0) */ + if (mtmp->mtame && rn2(mtmp->mtame)) mtmp->mtame--; + } + } else { + if (um_dist(mtmp->mx, mtmp->my, 5)) { + pline("%s leash snaps loose!", s_suffix(Monnam(mtmp))); + m_unleash(mtmp, FALSE); + } else { + You("pull on the leash."); + if (mtmp->data->msound != MS_SILENT) + switch (rn2(3)) { + case 0: growl(mtmp); break; + case 1: yelp(mtmp); break; + default: whimper(mtmp); break; } - } } - mtmp = mtmp->nmon; } } + } } #endif /* OVL0 */ #ifdef OVLB -boolean -wield_tool(obj) -struct obj *obj; -{ - if(welded(uwep)) { - /* Andreas Bormann - ihnp4!decvax!mcvax!unido!ab */ - if(flags.verbose) { - pline("Since your weapon is welded to your %s,", - bimanual(uwep) ? - (const char *)makeplural(body_part(HAND)) - : body_part(HAND)); - pline("you cannot wield that %s.", xname(obj)); - } - return(FALSE); - } - if (cantwield(youmonst.data)) { - You_cant("hold it strongly enough."); - return(FALSE); - } - /* Check shield */ - if (uarms && bimanual(obj)) { - You("cannot wield a two-handed tool while wearing a shield."); - return(FALSE); - } - if(uquiver == obj) setuqwep((struct obj *)0); - if(uswapwep == obj) { - (void) doswapweapon(); - /* If doswapweapon failed... */ - if(uswapwep == obj) return (FALSE); - } else { - You("now wield %s.", doname(obj)); - setuwep(obj); - } - if (uwep != obj) return(FALSE); /* rewielded old object after dying */ - /* applying weapon or tool that gets wielded ends two-weapon combat */ - if (u.twoweap) - untwoweapon(); - if (obj->oclass != WEAPON_CLASS) - unweapon = TRUE; - return(TRUE); -} - #define WEAK 3 /* from eat.c */ -static char look_str[] = "look %s."; +static const char look_str[] = "look %s."; STATIC_OVL int use_mirror(obj) @@ -875,7 +845,7 @@ use_candelabrum(obj) register struct obj *obj; { - char *s = obj->spe != 1 ? "candles" : "candle"; + const char *s = (obj->spe != 1) ? "candles" : "candle"; if(Underwater) { You("cannot make fire under water."); @@ -927,7 +897,7 @@ register struct obj *obj; { register struct obj *otmp; - char *s = obj->quan != 1 ? "candles" : "candle"; + const char *s = (obj->quan != 1) ? "candles" : "candle"; char qbuf[QBUFSZ]; if(u.uswallow) { @@ -971,8 +941,8 @@ (obj->quan > 1L) ? "them" : "it", (obj->quan > 1L) ? "them" : "it"); if (obj->quan < 7L && otmp->spe == 7) - pline("%s now has seven%s %s attached.", - The(xname(otmp)), otmp->lamplit ? " lit" : "", s); + pline("%s now has seven%s candles attached.", + The(xname(otmp)), otmp->lamplit ? " lit" : ""); /* candelabrum's light range might increase */ if (otmp->lamplit) obj_merge_light_sources(otmp, otmp); /* candles are no longer a separate light source */ @@ -1056,7 +1026,15 @@ return FALSE; if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind) pline("%s %s light!", Yname2(obj), otense(obj, "catch")); - begin_burn(obj, TRUE); + if (obj->otyp == POT_OIL) makeknown(obj->otyp); + if (obj->unpaid && costly_spot(u.ux, u.uy) && (obj->where == OBJ_INVENT)) { + /* if it catches while you have it, then it's your tough luck */ + check_unpaid(obj); + verbalize("That's in addition to the cost of %s %s, of course.", + Yname2(obj), obj->quan == 1 ? "itself" : "themselves"); + bill_dummy_object(obj); + } + begin_burn(obj, FALSE); return TRUE; } return FALSE; @@ -1181,7 +1159,7 @@ } } - if(!obj || (obj != uwep && !wield_tool(obj))) return 0; + if (!obj || !wield_tool(obj, "rub")) return 0; /* now uwep is obj */ if (uwep->otyp == MAGIC_LAMP) { @@ -1361,7 +1339,7 @@ if (In_sokoban(&u.uz)) change_luck(-1); - teleds(cc.x, cc.y); + teleds(cc.x, cc.y, TRUE); nomul(-1); nomovemsg = ""; morehungry(rnd(25)); @@ -1690,6 +1668,11 @@ { xchar x,y; + if (carried(obj) && u.uswallow) { + if (!quietly) + You("don't have enough room in here."); + return FALSE; + } x = cc->x; y = cc->y; if (!isok(x,y)) { if (!quietly) @@ -1719,6 +1702,11 @@ xchar x, y; coord cc; + if (u.uswallow) { + /* can't activate a figurine while swallowed */ + if (!figurine_location_checks(obj, (coord *)0, FALSE)) + return; + } if(!getdir((char *)0)) { flags.move = multi = 0; return; @@ -1729,12 +1717,13 @@ if (!figurine_location_checks(obj, &cc, FALSE)) return; You("%s and it transforms.", (u.dx||u.dy) ? "set the figurine beside you" : - (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) ? + (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || + is_pool(cc.x, cc.y)) ? "release the figurine" : (u.dz < 0 ? "toss the figurine into the air" : "set the figurine on the ground")); - (void) make_familiar(obj, u.ux+u.dx, u.uy+u.dy, FALSE); + (void) make_familiar(obj, cc.x, cc.y, FALSE); (void) stop_timer(FIG_TRANSFORM, (genericptr_t)obj); useup(obj); } @@ -1751,9 +1740,9 @@ char buf[BUFSZ]; if (Glib) { - dropx(obj); pline("%s from your %s.", Tobjnam(obj, "slip"), makeplural(body_part(FINGER))); + dropx(obj); return; } @@ -1761,9 +1750,9 @@ if ((obj->cursed || Fumbling) && !rn2(2)) { check_unpaid(obj); obj->spe--; - dropx(obj); pline("%s from your %s.", Tobjnam(obj, "slip"), makeplural(body_part(FINGER))); + dropx(obj); return; } otmp = getobj(lubricables, "grease"); @@ -1826,19 +1815,26 @@ { struct obj *obj; boolean do_scratch; - const char *streak_color; + const char *streak_color, *choices; char stonebuf[QBUFSZ]; static const char scritch[] = "\"scritch, scritch\""; - static char allowall[3] = { GOLD_CLASS, ALL_CLASSES, 0 }; + static const char allowall[3] = { COIN_CLASS, ALL_CLASSES, 0 }; + static const char justgems[3] = { ALLOW_NONE, GEM_CLASS, 0 }; #ifndef GOLDOBJ struct obj goldobj; #endif + /* in case it was acquired while blinded */ + if (!Blind) tstone->dknown = 1; + /* when the touchstone is fully known, don't bother listing extra + junk as likely candidates for rubbing */ + choices = (tstone->otyp == TOUCHSTONE && tstone->dknown && + objects[TOUCHSTONE].oc_name_known) ? justgems : allowall; Sprintf(stonebuf, "rub on the stone%s", plur(tstone->quan)); - if ((obj = getobj(allowall, stonebuf)) == 0) + if ((obj = getobj(choices, stonebuf)) == 0) return; #ifndef GOLDOBJ - if (obj->oclass == GOLD_CLASS) { + if (obj->oclass == COIN_CLASS) { u.ugold += obj->quan; /* keep botl up to date */ goldobj = *obj; dealloc_obj(obj); @@ -2066,10 +2062,8 @@ const char *msg_snap = "Snap!"; if (obj != uwep) { - if (!wield_tool(obj)) return 0; + if (!wield_tool(obj, "lash")) return 0; else res = 1; - /* prevent bashing msg */ - unweapon = FALSE; } if (!getdir((char *)0)) return res; @@ -2180,7 +2174,7 @@ if (proficient && rn2(proficient + 2)) { if (!mtmp || enexto(&cc, rx, ry, youmonst.data)) { You("yank yourself out of the pit!"); - teleds(cc.x, cc.y); + teleds(cc.x, cc.y, TRUE); u.utrap = 0; vision_full_recalc = 1; } @@ -2221,7 +2215,7 @@ } if (gotit) { obj_extract_self(otmp); - possibly_unwield(mtmp); + possibly_unwield(mtmp, FALSE); setmnotwielded(mtmp,otmp); switch (rn2(proficient + 1)) { @@ -2307,9 +2301,9 @@ static const char - *not_enough_room = "There's not enough room here to use that.", - *where_to_hit = "Where do you want to hit?", - *cant_see_spot = "won't hit anything if you can't see that spot."; + not_enough_room[] = "There's not enough room here to use that.", + where_to_hit[] = "Where do you want to hit?", + cant_see_spot[] = "won't hit anything if you can't see that spot."; /* Distance attacks by pole-weapons */ STATIC_OVL int @@ -2327,7 +2321,7 @@ return (0); } if (obj != uwep) { - if (!wield_tool(obj)) return(0); + if (!wield_tool(obj, "swing")) return(0); else res = 1; } /* assert(obj == uwep); */ @@ -2359,6 +2353,8 @@ if ((mtmp = m_at(cc.x, cc.y)) != (struct monst *)0) { int oldhp = mtmp->mhp; + bhitpos = cc; + check_caitiff(mtmp); (void) thitmonst(mtmp, uwep); /* check the monster's HP because thitmonst() doesn't return * an indication of whether it hit. Not perfect (what if it's a @@ -2372,12 +2368,50 @@ return (1); } +STATIC_OVL int +use_cream_pie(obj) +struct obj *obj; +{ + boolean wasblind = Blind; + boolean wascreamed = u.ucreamed; + boolean several = FALSE; + + if (obj->quan > 1L) { + several = TRUE; + obj = splitobj(obj, 1L); + } + if (Hallucination) + You("give yourself a facial."); + else + pline("You immerse your %s in %s%s.", body_part(FACE), + several ? "one of " : "", + several ? makeplural(the(xname(obj))) : the(xname(obj))); + if(can_blnd((struct monst*)0, &youmonst, AT_WEAP, obj)) { + int blindinc = rnd(25); + u.ucreamed += blindinc; + make_blinded(Blinded + (long)blindinc, FALSE); + if (!Blind || (Blind && wasblind)) + pline("There's %ssticky goop all over your %s.", + wascreamed ? "more " : "", + body_part(FACE)); + else /* Blind && !wasblind */ + You_cant("see through all the sticky goop on your %s.", + body_part(FACE)); + } + if (obj->unpaid) { + verbalize("You used it, you bought it!"); + bill_dummy_object(obj); + } + obj_extract_self(obj); + delobj(obj); + return(0); +} STATIC_OVL int use_grapple (obj) struct obj *obj; { - int res = 0, typ, max_range = 4; + int res = 0, typ, max_range = 4, tohit; coord cc; struct monst *mtmp; struct obj *otmp; @@ -2388,7 +2422,7 @@ return (0); } if (obj != uwep) { - if (!wield_tool(obj)) return(0); + if (!wield_tool(obj, "cast")) return(0); else res = 1; } /* assert(obj == uwep); */ @@ -2406,15 +2440,46 @@ else if (P_SKILL(typ) == P_SKILLED) max_range = 5; else max_range = 8; if (distu(cc.x, cc.y) > max_range) { - pline("Too far!"); - return (res); + pline("Too far!"); + return (res); } else if (!cansee(cc.x, cc.y)) { - You(cant_see_spot); - return (res); + You(cant_see_spot); + return (res); + } + + /* What do you want to hit? */ + tohit = rn2(5); + if (typ != P_NONE && P_SKILL(typ) >= P_SKILLED) { + winid tmpwin = create_nhwindow(NHW_MENU); + anything any; + char buf[BUFSZ]; + menu_item *selected; + + any.a_void = 0; /* set all bits to zero */ + any.a_int = 1; /* use index+1 (cant use 0) as identifier */ + start_menu(tmpwin); + any.a_int++; + Sprintf(buf, "an object on the %s", surface(cc.x, cc.y)); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + buf, MENU_UNSELECTED); + any.a_int++; + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + "a monster", MENU_UNSELECTED); + any.a_int++; + Sprintf(buf, "the %s", surface(cc.x, cc.y)); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + buf, MENU_UNSELECTED); + end_menu(tmpwin, "Aim for what?"); + tohit = rn2(4); + if (select_menu(tmpwin, PICK_ONE, &selected) > 0 && + rn2(P_SKILL(typ) > P_SKILLED ? 20 : 2)) + tohit = selected[0].item.a_int - 1; + free((genericptr_t)selected); + destroy_nhwindow(tmpwin); } /* What did you hit? */ - switch (rn2(5)) { + switch (tohit) { case 0: /* Trap */ /* FIXME -- untrap needs to deal with non-adjacent traps */ break; @@ -2475,6 +2540,7 @@ register struct monst *mon; int dmg, damage; boolean affects_objects; + boolean shop_damage = FALSE; int expltype = EXPL_MAGICAL; char confirm[QBUFSZ], the_wand[BUFSZ], buf[BUFSZ]; @@ -2562,10 +2628,17 @@ if (!isok(x,y)) continue; if (obj->otyp == WAN_DIGGING) { - if(dig_check(BY_OBJECT, FALSE, x, y)) + if(dig_check(BY_OBJECT, FALSE, x, y)) { + if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) { + /* normally, pits and holes don't anger guards, but they + * do if it's a wall or door that's being dug */ + watch_dig((struct monst *)0, x, y, TRUE); + if (*in_rooms(x,y,SHOPBASE)) shop_damage = TRUE; + } digactualhole(x, y, BY_OBJECT, (rn2(obj->spe) < 3 || !Can_dig_down(&u.uz)) ? PIT : HOLE); + } continue; } else if(obj->otyp == WAN_CREATE_MONSTER) { /* u.ux,u.uy creates it near you--x,y might create it in rock */ @@ -2598,6 +2671,10 @@ } } + /* Note: if player fell thru, this call is a no-op. + Damage is handled in digactualhole in that case */ + if (shop_damage) pay_for_damage("dig into", FALSE); + if (obj->otyp == WAN_LIGHT) litroom(TRUE, obj); /* only needs to be done once */ @@ -2621,17 +2698,40 @@ return FALSE; } +STATIC_OVL void +add_class(cl, class) +char *cl; +char class; +{ + char tmp[2]; + tmp[0] = class; + tmp[1] = '\0'; + Strcat(cl, tmp); +} + int doapply() { register struct obj *obj; register int res = 1; + char class_list[MAXOCLASSES+2]; if(check_capacity((char *)0)) return (0); - obj = getobj(carrying(POT_OIL) || uhave_graystone() - ? tools_too : tools, "use or apply"); + + if (carrying(POT_OIL) || uhave_graystone()) + Strcpy(class_list, tools_too); + else + Strcpy(class_list, tools); + if (carrying(CREAM_PIE) || carrying(EUCALYPTUS_LEAF)) + add_class(class_list, FOOD_CLASS); + + obj = getobj(class_list, "use or apply"); if(!obj) return 0; + if (obj->oartifact && !touch_artifact(obj, &youmonst)) + return 1; /* evading your grasp costs a turn; just be + grateful that you don't drop it as well */ + if (obj->oclass == WAND_CLASS) return do_break_wand(obj); @@ -2647,6 +2747,9 @@ ublindf->otyp == BLINDFOLD ? "wearing a blindfold" : "wearing lenses"); break; + case CREAM_PIE: + res = use_cream_pie(obj); + break; case BULLWHIP: res = use_whip(obj); break; @@ -2706,6 +2809,27 @@ case TIN_WHISTLE: use_whistle(obj); break; + case EUCALYPTUS_LEAF: + /* MRKR: Every Australian knows that a gum leaf makes an */ + /* excellent whistle, especially if your pet is a */ + /* tame kangaroo named Skippy. */ + if (obj->blessed) { + use_magic_whistle(obj); + /* sometimes the blessing will be worn off */ + if (!rn2(49)) { + if (!Blind) { + char buf[BUFSZ]; + + pline("%s %s %s.", Shk_Your(buf, obj), + aobjnam(obj, "glow"), hcolor("brown")); + obj->bknown = 1; + } + unbless(obj); + } + } else { + use_whistle(obj); + } + break; case STETHOSCOPE: res = use_stethoscope(obj); break; @@ -2798,9 +2922,12 @@ otmp->blessed = obj->blessed; otmp->cursed = obj->cursed; otmp->owt = weight(otmp); - otmp = hold_another_object(otmp, - (u.uswallow || Is_airlevel(&u.uz) || - u.uinwater || Is_waterlevel(&u.uz)) ? + otmp = hold_another_object(otmp, u.uswallow ? + "Oops! %s out of your reach!" : + (Is_airlevel(&u.uz) || + Is_waterlevel(&u.uz) || + levl[u.ux][u.uy].typ < IRONBARS || + levl[u.ux][u.uy].typ >= ICE) ? "Oops! %s away from you!" : "Oops! %s to the floor!", The(aobjnam(otmp, "slip")), @@ -2824,7 +2951,7 @@ if (is_pole(obj)) { res = use_pole(obj); break; - } else if (is_pick(obj) /* || is_axe(obj) */) { + } else if (is_pick(obj) || is_axe(obj)) { res = use_pick_axe(obj); break; } @@ -2841,7 +2968,8 @@ /* Keep track of unfixable troubles for purposes of messages saying you feel * great. */ -int unfixable_trouble_count(is_horn) +int +unfixable_trouble_count(is_horn) boolean is_horn; { int unfixable_trbl = 0; diff -Naurd ../nethack-3.4.0/src/artifact.c ./src/artifact.c --- ../nethack-3.4.0/src/artifact.c Wed Mar 20 23:43:00 2002 +++ ./src/artifact.c Mon Feb 24 15:25:05 2003 @@ -20,8 +20,11 @@ #define get_artifact(o) \ (((o)&&(o)->oartifact) ? &artilist[(int) (o)->oartifact] : 0) + STATIC_DCL int FDECL(spec_applies, (const struct artifact *,struct monst *)); STATIC_DCL int FDECL(arti_invoke, (struct obj*)); +STATIC_DCL boolean FDECL(Mb_hit, (struct monst *magr,struct monst *mdef, + struct obj *,int *,int,BOOLEAN_P,char *)); /* The amount added to the victim's total hit points to insure that the victim will be killed even after damage bonus/penalty adjustments. @@ -248,6 +251,34 @@ return((boolean)(arti && (arti->spfx & abil))); } +/* used so that callers don't need to known about SPFX_ codes */ +boolean +confers_luck(obj) +struct obj *obj; +{ + /* might as well check for this too */ + if (obj->otyp == LUCKSTONE) return TRUE; + + return (obj->oartifact && spec_ability(obj, SPFX_LUCK)); +} + +/* used to check whether a monster is getting reflection from an artifact */ +boolean +arti_reflects(obj) +struct obj *obj; +{ + const struct artifact *arti = get_artifact(obj); + + if (arti) { + /* while being worn */ + if ((obj->owornmask & ~W_ART) && (arti->spfx & SPFX_REFLECT)) + return TRUE; + /* just being carried */ + if (arti->cspfx & SPFX_REFLECT) return TRUE; + } + return FALSE; +} + #endif /* OVL0 */ #ifdef OVLB @@ -439,6 +470,7 @@ /* this assumes that no one else is using xray_range */ if (on) u.xray_range = 3; else u.xray_range = -1; + vision_full_recalc = 1; } if ((spfx & SPFX_REFLECT) && (wp_mask & W_WEP)) { if (on) EReflecting |= wp_mask; @@ -547,8 +579,9 @@ } else if (weap->spfx & SPFX_DFLAG1) { return ((ptr->mflags1 & weap->mtype) != 0L); } else if (weap->spfx & SPFX_DFLAG2) { - return ((ptr->mflags2 & weap->mtype) || - (yours && !Upolyd && (urace.selfmask & weap->mtype))); + return ((ptr->mflags2 & weap->mtype) || (yours && + ((!Upolyd && (urace.selfmask & weap->mtype)) || + ((weap->mtype & M2_WERE) && u.ulycn >= LOW_PM)))); } else if (weap->spfx & SPFX_DALIGN) { return yours ? (u.ualign.type != weap->alignment) : (ptr->maligntyp == A_NONE || @@ -688,6 +721,205 @@ #ifdef OVLB + + /* + * Magicbane's intrinsic magic is incompatible with normal + * enchantment magic. Thus, its effects have a negative + * dependence on spe. Against low mr victims, it typically + * does "double athame" damage, 2d4. Occasionally, it will + * cast unbalancing magic which effectively averages out to + * 4d4 damage (3d4 against high mr victims), for spe = 0. + * + * Prior to 3.4.1, the cancel (aka purge) effect always + * included the scare effect too; now it's one or the other. + * Likewise, the stun effect won't be combined with either + * of those two; it will be chosen separately or possibly + * used as a fallback when scare or cancel fails. + * + * [Historical note: a change to artifact_hit() for 3.4.0 + * unintentionally made all of Magicbane's special effects + * be blocked if the defender successfully saved against a + * stun attack. As of 3.4.1, those effects can occur but + * will be slightly less likely than they were in 3.3.x.] + */ +#define MB_MAX_DIEROLL 8 /* rolls above this aren't magical */ +static const char * const mb_verb[2][4] = { + { "probe", "stun", "scare", "cancel" }, + { "prod", "amaze", "tickle", "purge" }, +}; +#define MB_INDEX_PROBE 0 +#define MB_INDEX_STUN 1 +#define MB_INDEX_SCARE 2 +#define MB_INDEX_CANCEL 3 + +/* called when someone is being hit by Magicbane */ +STATIC_OVL boolean +Mb_hit(magr, mdef, mb, dmgptr, dieroll, vis, hittee) +struct monst *magr, *mdef; /* attacker and defender */ +struct obj *mb; /* Magicbane */ +int *dmgptr; /* extra damage target will suffer */ +int dieroll; /* d20 that has already scored a hit */ +boolean vis; /* whether the action can be seen */ +char *hittee; /* target's name: "you" or mon_nam(mdef) */ +{ + struct permonst *old_uasmon; + const char *verb; + boolean youattack = (magr == &youmonst), + youdefend = (mdef == &youmonst), + resisted = FALSE, do_stun, do_confuse, result; + int attack_indx, scare_dieroll = MB_MAX_DIEROLL / 2; + + result = FALSE; /* no message given yet */ + /* the most severe effects are less likely at higher enchantment */ + if (mb->spe >= 3) + scare_dieroll /= (1 << (mb->spe / 3)); + /* if target successfully resisted the artifact damage bonus, + reduce overall likelihood of the assorted special effects */ + if (!spec_dbon_applies) dieroll += 1; + + /* might stun even when attempting a more severe effect, but + in that case it will only happen if the other effect fails; + extra damage will apply regardless; 3.4.1: sometimes might + just probe even when it hasn't been enchanted */ + do_stun = (max(mb->spe,0) < rn2(spec_dbon_applies ? 11 : 7)); + + /* the special effects also boost physical damage; increments are + generally cumulative, but since the stun effect is based on a + different criterium its damage might not be included; the base + damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending + on target's resistance check against AD_STUN (handled by caller) + [note that a successful save against AD_STUN doesn't actually + prevent the target from ending up stunned] */ + attack_indx = MB_INDEX_PROBE; + *dmgptr += rnd(4); /* (2..3)d4 */ + if (do_stun) { + attack_indx = MB_INDEX_STUN; + *dmgptr += rnd(4); /* (3..4)d4 */ + } + if (dieroll <= scare_dieroll) { + attack_indx = MB_INDEX_SCARE; + *dmgptr += rnd(4); /* (3..5)d4 */ + } + if (dieroll <= (scare_dieroll / 2)) { + attack_indx = MB_INDEX_CANCEL; + *dmgptr += rnd(4); /* (4..6)d4 */ + } + + /* give the hit message prior to inflicting the effects */ + verb = mb_verb[!!Hallucination][attack_indx]; + if (youattack || youdefend || vis) { + result = TRUE; + pline_The("magic-absorbing blade %s %s!", + vtense((const char *)0, verb), hittee); + /* assume probing has some sort of noticeable feedback + even if it is being done by one monster to another */ + if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef)) + map_invisible(mdef->mx, mdef->my); + } + + /* now perform special effects */ + switch (attack_indx) { + case MB_INDEX_CANCEL: + old_uasmon = youmonst.data; + if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) { + resisted = TRUE; + } else { + do_stun = FALSE; + if (youdefend) { + if (youmonst.data != old_uasmon) + *dmgptr = 0; /* rehumanized, so no more damage */ + if (u.uenmax > 0) { + You("lose magical energy!"); + u.uenmax--; + if (u.uen > 0) u.uen--; + flags.botl = 1; + } + } else { + if (mdef->data == &mons[PM_CLAY_GOLEM]) + mdef->mhp = 1; /* cancelled clay golems will die */ + if (youattack && attacktype(mdef->data, AT_MAGC)) { + You("absorb magical energy!"); + u.uenmax++; + u.uen++; + flags.botl = 1; + } + } + } + break; + + case MB_INDEX_SCARE: + if (youdefend) { + if (Antimagic) { + resisted = TRUE; + } else { + nomul(-3); + nomovemsg = ""; + if (magr && magr == u.ustuck && sticks(youmonst.data)) { + u.ustuck = (struct monst *)0; + You("release %s!", mon_nam(magr)); + } + } + } else { + if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL)) + resisted = TRUE; + else + monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr)); + } + if (!resisted) do_stun = FALSE; + break; + + case MB_INDEX_STUN: + do_stun = TRUE; /* (this is redundant...) */ + break; + + case MB_INDEX_PROBE: + if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) { + pline_The("%s is insightful.", verb); + /* pre-damage status */ + probe_monster(mdef); + } + break; + } + /* stun if that was selected and a worse effect didn't occur */ + if (do_stun) { + if (youdefend) + make_stunned((HStun + 3), FALSE); + else + mdef->mstun = 1; + /* avoid extra stun message below if we used mb_verb["stun"] above */ + if (attack_indx == MB_INDEX_STUN) do_stun = FALSE; + } + /* lastly, all this magic can be confusing... */ + do_confuse = !rn2(12); + if (do_confuse) { + if (youdefend) + make_confused(HConfusion + 4, FALSE); + else + mdef->mconf = 1; + } + + if (youattack || youdefend || vis) { + (void) upstart(hittee); /* capitalize */ + if (resisted) { + pline("%s %s!", hittee, vtense(hittee, "resist")); + shieldeff(youdefend ? u.ux : mdef->mx, + youdefend ? u.uy : mdef->my); + } + if ((do_stun || do_confuse) && flags.verbose) { + char buf[BUFSZ]; + + buf[0] = '\0'; + if (do_stun) Strcat(buf, "stunned"); + if (do_stun && do_confuse) Strcat(buf, " and "); + if (do_confuse) Strcat(buf, "confused"); + pline("%s %s %s%c", hittee, vtense(hittee, "are"), + buf, (do_stun && do_confuse) ? '!' : '.'); + } + } + + return result; +} + /* Function used when someone attacks someone else with an artifact * weapon. Only adds the special (artifact) damage, and returns a 1 if it * did something special (in which case the caller won't print the normal @@ -725,7 +957,9 @@ return FALSE; } - realizes_damage = (youdefend || vis); + realizes_damage = (youdefend || vis || + /* feel the effect even if not seen */ + (youattack && mdef == u.ustuck)); /* the four basic attacks: fire, cold, shock and missiles */ if (attacks(AD_FIRE, otmp)) { @@ -750,192 +984,34 @@ return realizes_damage; } if (attacks(AD_ELEC, otmp)) { - if (realizes_damage) { - if (youattack ? otmp != uwep : !spec_dbon_applies) - pline("%s %s%c", Tobjnam(otmp, "hit"), + if (realizes_damage) + pline_The("massive hammer hits%s %s%c", + !spec_dbon_applies ? "" : "! Lightning strikes", hittee, !spec_dbon_applies ? '.' : '!'); - if (spec_dbon_applies) - pline("Lightning strikes %s!", hittee); - } if (!rn2(5)) (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC); if (!rn2(5)) (void) destroy_mitem(mdef, WAND_CLASS, AD_ELEC); return realizes_damage; } if (attacks(AD_MAGM, otmp)) { - if (realizes_damage) { - if (youattack ? otmp != uwep : !spec_dbon_applies) - pline("%s %s%c", Tobjnam(otmp, "hit"), + if (realizes_damage) + pline_The("imaginary widget hits%s %s%c", + !spec_dbon_applies ? "" : + "! A hail of magic missiles strikes", hittee, !spec_dbon_applies ? '.' : '!'); - if (spec_dbon_applies) - pline("A hail of magic missiles strikes %s!", hittee); - } return realizes_damage; } + if (attacks(AD_STUN, otmp) && dieroll <= MB_MAX_DIEROLL) { + /* Magicbane's special attacks (possibly modifies hittee[]) */ + return Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee); + } + if (!spec_dbon_applies) { /* since damage bonus didn't apply, nothing more to do; no further attacks have side-effects on inventory */ return FALSE; } - /* - * Magicbane's intrinsic magic is incompatible with normal - * enchantment magic. Thus, its effects have a negative - * dependence on spe. Against low mr victims, it typically - * does "double athame" damage, 2d4. Occasionally, it will - * cast unbalancing magic which effectively averages out to - * 4d4 damage (2.5d4 against high mr victims), for spe = 0. - */ - -#define MB_MAX_DIEROLL 8 /* rolls above this aren't magical */ -#define MB_INDEX_INIT (-1) -#define MB_INDEX_PROBE 0 -#define MB_INDEX_STUN 1 -#define MB_INDEX_SCARE 2 -#define MB_INDEX_PURGE 3 -#define MB_RESIST_ATTACK (resist_index = attack_index) -#define MB_RESISTED_ATTACK (resist_index == attack_index) -#define MB_UWEP_ATTACK (youattack && (otmp == uwep)) - - if (attacks(AD_STUN, otmp) && (dieroll <= MB_MAX_DIEROLL)) { - int attack_index = MB_INDEX_INIT; - int resist_index = MB_INDEX_INIT; - int scare_dieroll = MB_MAX_DIEROLL / 2; - - if (otmp->spe >= 3) - scare_dieroll /= (1 << (otmp->spe / 3)); - - *dmgptr += rnd(4); /* 3d4 */ - - if (otmp->spe > rn2(10)) /* probe */ - attack_index = MB_INDEX_PROBE; - else { /* stun */ - attack_index = MB_INDEX_STUN; - *dmgptr += rnd(4); /* 4d4 */ - - if (youdefend) - make_stunned((HStun + 3), FALSE); - else - mdef->mstun = 1; - } - if (dieroll <= scare_dieroll) { /* scare */ - attack_index = MB_INDEX_SCARE; - *dmgptr += rnd(4); /* 5d4 */ - - if (youdefend) { - if (Antimagic) - MB_RESIST_ATTACK; - else { - nomul(-3); - nomovemsg = ""; - if (magr && magr == u.ustuck - && sticks(youmonst.data)) { - u.ustuck = (struct monst *)0; - You("release %s!", mon_nam(magr)); - } - } - } else if (youattack) { - if (rn2(2) && resist(mdef,SPBOOK_CLASS,0,0)) { - MB_RESIST_ATTACK; - } else { - monflee(mdef, 3, FALSE, TRUE); - } - } - } - if (dieroll <= (scare_dieroll / 2)) { /* purge */ - struct obj *ospell; - struct permonst *old_uasmon = youmonst.data; - - attack_index = MB_INDEX_PURGE; - *dmgptr += rnd(4); /* 6d4 */ - - /* Create a fake spell object, ala spell.c */ - ospell = mksobj(SPE_CANCELLATION, FALSE, FALSE); - ospell->blessed = ospell->cursed = 0; - ospell->quan = 20L; - - cancel_monst(mdef, ospell, youattack, FALSE, FALSE); - - if (youdefend) { - if (old_uasmon != youmonst.data) - /* rehumanized, no more damage */ - *dmgptr = 0; - if (Antimagic) - MB_RESIST_ATTACK; - } else { - if (!mdef->mcan) - MB_RESIST_ATTACK; - - /* cancelled clay golems will die ... */ - else if (mdef->data == &mons[PM_CLAY_GOLEM]) - mdef->mhp = 1; - } - - obfree(ospell, (struct obj *)0); - } - - if (youdefend || mdef->mhp > 0) { /* ??? -dkh- */ - static const char *mb_verb[4] = - {"probe", "stun", "scare", "purge"}; - - if (youattack || youdefend || vis) { - pline_The("magic-absorbing blade %ss %s!", - mb_verb[attack_index], hittee); - - if (MB_RESISTED_ATTACK) { - pline("%s resist%s!", - youdefend ? "You" : Monnam(mdef), - youdefend ? "" : "s"); - - shieldeff(youdefend ? u.ux : mdef->mx, - youdefend ? u.uy : mdef->my); - } - } - - /* Much ado about nothing. More magic fanfare! */ - if (MB_UWEP_ATTACK) { - if (attack_index == MB_INDEX_PURGE) { - if (!MB_RESISTED_ATTACK && - attacktype(mdef->data, AT_MAGC)) { - You("absorb magical energy!"); - u.uenmax++; - u.uen++; - flags.botl = 1; - } - } else if (attack_index == MB_INDEX_PROBE) { - if (!rn2(4 * otmp->spe)) { - pline_The("probe is insightful!"); - if (!canspotmon(mdef)) - map_invisible(u.ux+u.dx,u.uy+u.dy); - /* pre-damage status */ - probe_monster(mdef); - } - } - } else if (youdefend && !MB_RESISTED_ATTACK - && (attack_index == MB_INDEX_PURGE)) { - You("lose magical energy!"); - if (u.uenmax > 0) u.uenmax--; - if (u.uen > 0) u.uen--; - flags.botl = 1; - } - - /* all this magic is confusing ... */ - if (!rn2(12)) { - if (youdefend) - make_confused((HConfusion + 4), FALSE); - else - mdef->mconf = 1; - - if (youattack || youdefend || vis) - pline("%s %s confused.", - youdefend ? "You" : Monnam(mdef), - youdefend ? "are" : "is"); - } - } - return TRUE; - } - /* end of Magicbane code */ - /* We really want "on a natural 20" but Nethack does it in */ /* reverse from AD&D. */ if (spec_ability(otmp, SPFX_BEHEAD)) { @@ -986,7 +1062,7 @@ } } else if (otmp->oartifact == ART_VORPAL_BLADE && (dieroll == 1 || mdef->data == &mons[PM_JABBERWOCK])) { - static const char *behead_msg[2] = { + static const char * const behead_msg[2] = { "%s beheads %s!", "%s decapitates %s!" }; @@ -1043,7 +1119,7 @@ if (vis) { if(otmp->oartifact == ART_STORMBRINGER) pline_The("%s blade draws the life from %s!", - hcolor(Black), + hcolor(NH_BLACK), mon_nam(mdef)); else pline("%s draws the life from %s!", @@ -1070,7 +1146,7 @@ "unholy blade" : "object"); else if (otmp->oartifact == ART_STORMBRINGER) pline_The("%s blade drains your life!", - hcolor(Black)); + hcolor(NH_BLACK)); else pline("%s drains your life!", The(distant_name(otmp, xname))); @@ -1095,7 +1171,8 @@ register struct obj *obj; obj = getobj(invoke_types, "invoke"); - if(!obj) return 0; + if (!obj) return 0; + if (obj->oartifact && !touch_artifact(obj, &youmonst)) return 1; return arti_invoke(obj); } @@ -1138,7 +1215,7 @@ long creamed = (long)u.ucreamed; if (Upolyd) healamt = (u.mhmax + 1 - u.mh) / 2; - if (healamt || Sick || Blinded > creamed) + if (healamt || Sick || Slimed || Blinded > creamed) You_feel("better."); else goto nothing_special; @@ -1268,13 +1345,16 @@ } } } else { - long cprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI); - boolean on = (cprop & W_ARTI) != 0; /* true if invoked prop just set */ + long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI), + iprop = u.uprops[oart->inv_prop].intrinsic; + boolean on = (eprop & W_ARTI) != 0; /* true if invoked prop just set */ if(on && obj->age > monstermoves) { /* the artifact is tired :-) */ u.uprops[oart->inv_prop].extrinsic ^= W_ARTI; You_feel("that %s is ignoring you.", the(xname(obj))); + /* can't just keep repeatedly trying */ + obj->age += (long) d(3,10); return 1; } else if(!on) { /* when turning off property, determine downtime */ @@ -1282,7 +1362,7 @@ obj->age = monstermoves + rnz(100); } - if(cprop & ~W_ARTI) { + if ((eprop & ~W_ARTI) || iprop) { nothing_special: /* you had the property from some other source too */ if (carried(obj)) @@ -1301,15 +1381,13 @@ } else (void) float_down(I_SPECIAL|TIMEOUT, W_ARTI); break; case INVIS: - if (!See_invisible && !Blind) { - newsym(u.ux,u.uy); - if (on) { - Your("body takes on a %s transparency...", - Hallucination ? "normal" : "strange"); - } else { - Your("body seems to unfade..."); - } - } else goto nothing_special; + if (BInvis || Blind) goto nothing_special; + newsym(u.ux, u.uy); + if (on) + Your("body takes on a %s transparency...", + Hallucination ? "normal" : "strange"); + else + Your("body seems to unfade..."); break; } } @@ -1327,7 +1405,8 @@ } /* KMH -- Talking artifacts are finally implemented */ -void arti_speak(obj) +void +arti_speak(obj) struct obj *obj; { register const struct artifact *oart = get_artifact(obj); diff -Naurd ../nethack-3.4.0/src/attrib.c ./src/attrib.c --- ../nethack-3.4.0/src/attrib.c Wed Mar 20 23:43:00 2002 +++ ./src/attrib.c Mon Feb 24 15:25:05 2003 @@ -1,11 +1,10 @@ -/* SCCS Id: @(#)attrib.c 3.4 2000/05/17 */ +/* SCCS Id: @(#)attrib.c 3.4 2002/10/07 */ /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* attribute modification routines. */ #include "hack.h" -#include "artifact.h" /* #define DEBUG */ /* uncomment for debugging info */ @@ -13,10 +12,10 @@ /* part of the output on gain or loss of attribute */ static -const char *plusattr[] = { +const char * const plusattr[] = { "strong", "smart", "wise", "agile", "tough", "charismatic" }, - *minusattr[] = { + * const minusattr[] = { "weak", "stupid", "foolish", "clumsy", "fragile", "repulsive" }; @@ -99,6 +98,7 @@ static long next_check = 600L; /* arbitrary first setting */ STATIC_DCL void NDECL(exerper); +STATIC_DCL void FDECL(postadjabil, (long *)); /* adjust an attribute; return TRUE if change is made, FALSE otherwise */ boolean @@ -211,9 +211,8 @@ register struct obj *otmp; register long bonchance = 0; - for(otmp = invent; otmp; otmp=otmp->nobj) - if (otmp->otyp == LUCKSTONE - || (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) { + for (otmp = invent; otmp; otmp = otmp->nobj) + if (confers_luck(otmp)) { if (otmp->cursed) bonchance -= otmp->quan; else if (otmp->blessed) bonchance += otmp->quan; else if (parameter) bonchance += otmp->quan; @@ -318,9 +317,15 @@ pline("exerper: Hunger checks"); #endif switch (hs) { - case SATIATED: exercise(A_DEX, FALSE); break; + case SATIATED: exercise(A_DEX, FALSE); + if (Role_if(PM_MONK)) + exercise(A_WIS, FALSE); + break; case NOT_HUNGRY: exercise(A_CON, TRUE); break; - case WEAK: exercise(A_STR, FALSE); break; + case WEAK: exercise(A_STR, FALSE); + if (Role_if(PM_MONK)) /* fasting */ + exercise(A_WIS, TRUE); + break; case FAINTING: case FAINTED: exercise(A_CON, FALSE); break; } @@ -517,6 +522,16 @@ (void)encumber_msg(); } +STATIC_OVL +void +postadjabil(ability) +long *ability; +{ + if (!ability) return; + if (ability == &(HWarning) || ability == &(HSee_invisible)) + see_monsters(); +} + void adjabil(oldlevel,newlevel) int oldlevel, newlevel; @@ -554,6 +569,7 @@ } while (abil || rabil) { + long prevabil; /* Have we finished with the intrinsics list? */ if (!abil || !abil->ability) { /* Try the race intrinsics */ @@ -562,7 +578,7 @@ rabil = 0; mask = FROMRACE; } - + prevabil = *(abil->ability); if(oldlevel < abil->ulevel && newlevel >= abil->ulevel) { /* Abilities gained at level 1 can never be lost * via level loss, only via means that remove _any_ @@ -587,6 +603,8 @@ You_feel("less %s!", abil->gainstr); } } + if (prevabil != *(abil->ability)) /* it changed */ + postadjabil(abil->ability); abil++; } diff -Naurd ../nethack-3.4.0/src/ball.c ./src/ball.c --- ../nethack-3.4.0/src/ball.c Wed Mar 20 23:43:00 2002 +++ ./src/ball.c Mon Feb 24 15:25:05 2003 @@ -38,7 +38,7 @@ } else if (flags.verbose) Your("%s does not protect you.", xname(uarmh)); } - losehp(dmg, "Crunched in the head by an iron ball", + losehp(dmg, "crunched in the head by an iron ball", NO_KILLER_PREFIX); } } @@ -343,19 +343,30 @@ } } -/* return TRUE if ball could be dragged +/* return TRUE if the caller needs to place the ball and chain down again * * Should not be called while swallowed. Should be called before movement, * because we might want to move the ball or chain to the hero's old position. + * + * It is called if we are moving. It is also called if we are teleporting + * *if* the ball doesn't move and we thus must drag the chain. It is not + * called for ordinary teleportation. + * + * allow_drag is only used in the ugly special case where teleporting must + * drag the chain, while an identical-looking movement must drag both the ball + * and chain. */ boolean -drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay) +drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay, + allow_drag) xchar x, y; int *bc_control; xchar *ballx, *bally, *chainx, *chainy; boolean *cause_delay; +boolean allow_drag; { struct trap *t = (struct trap *)0; + boolean already_in_rock; *ballx = uball->ox; *bally = uball->oy; @@ -371,10 +382,11 @@ /* only need to move the chain? */ if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) { + xchar oldchainx = uchain->ox, oldchainy = uchain->oy; *bc_control = BC_CHAIN; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); if (carried(uball)) { - /* move chain only if necessary; assume they didn't teleport */ + /* move chain only if necessary */ if (distmin(x, y, uchain->ox, uchain->oy) > 1) { *chainx = u.ux; *chainy = u.uy; @@ -383,11 +395,31 @@ } #define CHAIN_IN_MIDDLE(chx, chy) \ (distmin(x, y, chx, chy) <= 1 && distmin(chx, chy, uball->ox, uball->oy) <= 1) +#define IS_CHAIN_ROCK(x,y) \ +(IS_ROCK(levl[x][y].typ) || (IS_DOOR(levl[x][y].typ) && \ + (levl[x][y].doormask & (D_CLOSED|D_LOCKED)))) +/* Don't ever move the chain into solid rock. If we have to, then instead + * undo the move_bc() and jump to the drag ball code. Note that this also + * means the "cannot carry and drag" message will not appear, since unless we + * moved at least two squares there is no possibility of the chain position + * being in solid rock. + */ +#define SKIP_TO_DRAG { *chainx = oldchainx; *chainy = oldchainy; \ + move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \ + goto drag; } + if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy) + || IS_CHAIN_ROCK(uball->ox, uball->oy)) + already_in_rock = TRUE; + else + already_in_rock = FALSE; + switch(dist2(x, y, uball->ox, uball->oy)) { /* two spaces diagonal from ball, move chain inbetween */ case 8: *chainx = (uball->ox + x)/2; *chainy = (uball->oy + y)/2; + if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) + SKIP_TO_DRAG; break; /* player is distance 2/1 from ball; move chain to one of the @@ -410,7 +442,47 @@ tempy = y; tempy2 = uball->oy; } - if (dist2(tempx, tempy, uchain->ox, uchain->oy) < + if (IS_CHAIN_ROCK(tempx, tempy) && + !IS_CHAIN_ROCK(tempx2, tempy2) && + !already_in_rock) { + if (allow_drag) { + /* Avoid pathological case *if* not teleporting: + * 0 0_ + * _X move northeast -----> X@ + * @ + */ + if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 && + dist2(x, y, tempx, tempy) == 1) + SKIP_TO_DRAG; + /* Avoid pathological case *if* not teleporting: + * 0 0 + * _X move east -----> X_ + * @ @ + */ + if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 && + dist2(x, y, tempx, tempy) == 2) + SKIP_TO_DRAG; + } + *chainx = tempx2; + *chainy = tempy2; + } else if (!IS_CHAIN_ROCK(tempx, tempy) && + IS_CHAIN_ROCK(tempx2, tempy2) && + !already_in_rock) { + if (allow_drag) { + if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 && + dist2(x, y, tempx2, tempy2) == 1) + SKIP_TO_DRAG; + if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 && + dist2(x, y, tempx2, tempy2) == 2) + SKIP_TO_DRAG; + } + *chainx = tempx; + *chainy = tempy; + } else if (IS_CHAIN_ROCK(tempx, tempy) && + IS_CHAIN_ROCK(tempx2, tempy2) && + !already_in_rock) { + SKIP_TO_DRAG; + } else if (dist2(tempx, tempy, uchain->ox, uchain->oy) < dist2(tempx2, tempy2, uchain->ox, uchain->oy) || ((dist2(tempx, tempy, uchain->ox, uchain->oy) == dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) { @@ -428,8 +500,10 @@ case 4: if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy)) break; - *chainx = (x + uchain->ox)/2; - *chainy = (y + uchain->oy)/2; + *chainx = (x + uball->ox)/2; + *chainy = (y + uball->oy)/2; + if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) + SKIP_TO_DRAG; break; /* ball is one space diagonal from player. Check for the @@ -447,6 +521,8 @@ *chainx = uball->ox; else *chainy = uball->oy; + if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) + SKIP_TO_DRAG; break; } /* fall through */ @@ -470,11 +546,15 @@ default: impossible("bad chain movement"); break; } +#undef SKIP_TO_DRAG +#undef IS_CHAIN_ROCK #undef CHAIN_IN_MIDDLE return TRUE; } - if (near_capacity() > SLT_ENCUMBER) { +drag: + + if (near_capacity() > SLT_ENCUMBER && dist2(x, y, u.ux, u.uy) <= 2) { You("cannot %sdrag the heavy iron ball.", invent ? "carry all that and also " : ""); nomul(0); @@ -527,13 +607,25 @@ } } - *bc_control = BC_BALL|BC_CHAIN;; + *bc_control = BC_BALL|BC_CHAIN; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); - *ballx = uchain->ox; - *bally = uchain->oy; - *chainx = u.ux; - *chainy = u.uy; + if (dist2(x, y, u.ux, u.uy) > 2) { + /* Awful case: we're still in range of the ball, so we thought we + * could only move the chain, but it turned out that the target + * square for the chain was rock, so we had to drag it instead. + * But we can't drag it either, because we teleported and are more + * than one square from our old position. Revert to the teleport + * behavior. + */ + *ballx = *chainx = x; + *bally = *chainy = y; + } else { + *ballx = uchain->ox; + *bally = uchain->oy; + *chainx = u.ux; + *chainy = u.uy; + } *cause_delay = TRUE; return TRUE; } diff -Naurd ../nethack-3.4.0/src/bones.c ./src/bones.c --- ../nethack-3.4.0/src/bones.c Wed Mar 20 23:43:00 2002 +++ ./src/bones.c Mon Feb 24 15:25:05 2003 @@ -165,6 +165,9 @@ return FALSE; if (no_bones_level(&u.uz)) return FALSE; /* no bones for specific levels */ + if (u.uswallow) { + return FALSE; /* no bones when swallowed */ + } if (!Is_branchlev(&u.uz)) { /* no bones on non-branches with portals */ for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) @@ -194,9 +197,11 @@ struct permonst *mptr; struct fruit *f; char c, *bonesid; + char whynot[BUFSZ]; /* caller has already checked `can_make_bones()' */ + clear_bypasses(); fd = open_bonesfile(&u.uz, &bonesid); if (fd >= 0) { (void) close(fd); @@ -308,12 +313,16 @@ levl[x][y].glyph = cmap_to_glyph(S_stone); } - fd = create_bonesfile(&u.uz, &bonesid); + fd = create_bonesfile(&u.uz, &bonesid, whynot); if(fd < 0) { #ifdef WIZARD if(wizard) - pline("Cannot create bones file - create failed"); + pline("%s", whynot); #endif + /* bones file creation problems are silent to the player. + * Keep it that way, but place a clue into the paniclog. + */ + paniclog("savebones", whynot); return; } c = (char) (strlen(bonesid) + 1); @@ -397,15 +406,18 @@ #endif mread(fd, (genericptr_t) &c, sizeof c); /* length incl. '\0' */ mread(fd, (genericptr_t) oldbonesid, (unsigned) c); /* DD.nnn */ - if (strcmp(bonesid, oldbonesid)) { + if (strcmp(bonesid, oldbonesid) != 0) { + char errbuf[BUFSZ]; + + Sprintf(errbuf, "This is bones level '%s', not '%s'!", + oldbonesid, bonesid); #ifdef WIZARD if (wizard) { - pline("This is bones level '%s', not '%s'!", - oldbonesid, bonesid); + pline("%s", errbuf); ok = FALSE; /* won't die of trickery */ } #endif - trickery(); + trickery(errbuf); } else { register struct monst *mtmp; int mndx; diff -Naurd ../nethack-3.4.0/src/botl.c ./src/botl.c --- ../nethack-3.4.0/src/botl.c Wed Mar 20 23:43:01 2002 +++ ./src/botl.c Mon Feb 24 15:25:05 2003 @@ -7,7 +7,7 @@ #ifdef OVL0 extern const char *hu_stat[]; /* defined in eat.c */ -const char *enc_stat[] = { +const char * const enc_stat[] = { "", "Burdened", "Stressed", @@ -45,7 +45,8 @@ #ifdef OVL1 /* convert experience level (1..30) to rank index (0..8) */ -int xlev_to_rank(xlev) +int +xlev_to_rank(xlev) int xlev; { return (xlev <= 2) ? 0 : (xlev <= 30) ? ((xlev + 2) / 4) : 8; @@ -53,7 +54,8 @@ #if 0 /* not currently needed */ /* convert rank index (0..8) to experience level (1..30) */ -int rank_to_xlev(rank) +int +rank_to_xlev(rank) int rank; { return (rank <= 0) ? 1 : (rank <= 8) ? ((rank * 4) - 2) : 30; @@ -254,7 +256,7 @@ if(hp < 0) hp = 0; (void) describe_level(newbot2); Sprintf(nb = eos(newbot2), - "%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", oc_syms[GOLD_CLASS], + "%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", oc_syms[COIN_CLASS], #ifndef GOLDOBJ u.ugold, #else diff -Naurd ../nethack-3.4.0/src/cmd.c ./src/cmd.c --- ../nethack-3.4.0/src/cmd.c Wed Mar 20 23:43:01 2002 +++ ./src/cmd.c Mon Feb 24 15:25:05 2003 @@ -22,7 +22,7 @@ * module you are trying to debug) or things are going to get rather * hard to link :-) */ -extern void NDECL(wiz_debug_cmd); +extern int NDECL(wiz_debug_cmd); #endif #ifdef DUMB /* stuff commented out in extern.h, but needed here */ @@ -115,6 +115,7 @@ STATIC_PTR int NDECL(wiz_genesis); STATIC_PTR int NDECL(wiz_where); STATIC_PTR int NDECL(wiz_detect); +STATIC_PTR int NDECL(wiz_panic); STATIC_PTR int NDECL(wiz_polyself); STATIC_PTR int NDECL(wiz_level_tele); STATIC_PTR int NDECL(wiz_level_change); @@ -131,14 +132,18 @@ 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); +# ifdef PORT_DEBUG +STATIC_DCL int NDECL(wiz_port_debug); +# endif # endif STATIC_PTR int NDECL(enter_explore_mode); STATIC_PTR int NDECL(doattributes); STATIC_PTR int NDECL(doconduct); /**/ -STATIC_PTR void NDECL(minimal_enlightenment); +STATIC_PTR boolean NDECL(minimal_enlightenment); #ifdef OVLB STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *)); +STATIC_DCL char *FDECL(enlght_combatinc, (const char *,int,int,char *)); #ifdef UNIX static void NDECL(end_of_input); #endif @@ -147,6 +152,7 @@ static const char* readchar_queue=""; STATIC_DCL char *NDECL(parse); +STATIC_DCL boolean FDECL(help_dir, (CHAR_P,const char *)); #ifdef OVL1 @@ -435,6 +441,7 @@ } #endif +/* #monster command - use special monster ability while polymorphed */ STATIC_PTR int domonability() { @@ -484,6 +491,8 @@ } #ifdef WIZARD + +/* ^W command - wish for something */ STATIC_PTR int wiz_wish() /* Unlimited wishes for debug mode by Paul Polderman */ { @@ -499,6 +508,7 @@ return 0; } +/* ^I command - identify hero's inventory */ STATIC_PTR int wiz_identify() { @@ -507,23 +517,29 @@ return 0; } -/* reveal the level map and any traps on it */ +/* ^F command - reveal the level map and any traps on it */ STATIC_PTR int wiz_map() { if (wizard) { struct trap *t; + long save_Hconf = HConfusion, + save_Hhallu = HHallucination; + HConfusion = HHallucination = 0L; for (t = ftrap; t != 0; t = t->ntrap) { t->tseen = 1; map_trap(t, TRUE); } do_mapping(); + HConfusion = save_Hconf; + HHallucination = save_Hhallu; } else pline("Unavailable command '^F'."); return 0; } +/* ^G command - generate monster(s); a count prefix will be honored */ STATIC_PTR int wiz_genesis() { @@ -532,6 +548,7 @@ return 0; } +/* ^O command - display dungeon layout */ STATIC_PTR int wiz_where() { @@ -540,6 +557,7 @@ return 0; } +/* ^E command - detect unseen (secret doors, traps, hidden monsters) */ STATIC_PTR int wiz_detect() { @@ -548,6 +566,7 @@ return 0; } +/* ^V command - level teleport */ STATIC_PTR int wiz_level_tele() { @@ -556,6 +575,7 @@ return 0; } +/* #monpolycontrol command - choose new form for shapechangers, polymorphees */ STATIC_PTR int wiz_mon_polycontrol() { @@ -565,6 +585,7 @@ return 0; } +/* #levelchange command - adjust hero's experience level */ STATIC_PTR int wiz_level_change() { @@ -590,7 +611,7 @@ } if (newlevel < 1) newlevel = 1; while (u.ulevel > newlevel) - losexp((const char *)0); + losexp("#levelchange"); } else { if (u.ulevel >= MAXULEV) { You("are already as experienced as you can get."); @@ -604,6 +625,16 @@ return 0; } +/* #panic command - test program's panic handling */ +STATIC_PTR int +wiz_panic() +{ + if (yn("Do you want to call panic() and end your game?") == 'y') + panic("crash test."); + return 0; +} + +/* #polyself command - change hero's form */ STATIC_PTR int wiz_polyself() { @@ -611,6 +642,7 @@ return 0; } +/* #seenv command */ STATIC_PTR int wiz_show_seenv() { @@ -652,6 +684,7 @@ return 0; } +/* #vision command */ STATIC_PTR int wiz_show_vision() { @@ -688,6 +721,7 @@ return 0; } +/* #wmode command */ STATIC_PTR int wiz_show_wmodes() { @@ -725,13 +759,13 @@ /* -enlightenment and conduct- */ static winid en_win; static const char - *You_ = "You ", - *are = "are ", *were = "were ", - *have = "have ", *had = "had ", - *can = "can ", *could = "could "; + 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 "; + have_been[] = "have been ", + have_never[] = "have never ", never[] = "never "; #define enl_msg(prefix,present,past,suffix) \ enlght_line(prefix, final ? past : present, suffix) @@ -752,6 +786,43 @@ putstr(en_win, 0, buf); } +/* format increased damage or chance to hit */ +static char * +enlght_combatinc(inctyp, incamt, final, outbuf) +const char *inctyp; +int incamt, final; +char *outbuf; +{ + char numbuf[24]; + const char *modif, *bonus; + + if (final +#ifdef WIZARD + || wizard +#endif + ) { + Sprintf(numbuf, "%s%d", + (incamt > 0) ? "+" : "", incamt); + modif = (const char *) numbuf; + } else { + int absamt = abs(incamt); + + if (absamt <= 3) modif = "small"; + else if (absamt <= 6) modif = "moderate"; + else if (absamt <= 12) modif = "large"; + else modif = "huge"; + } + bonus = (incamt > 0) ? "bonus" : "penalty"; + /* "bonus to hit" vs "damage bonus" */ + if (!strcmp(inctyp, "damage")) { + const char *ctmp = inctyp; + inctyp = bonus; + bonus = ctmp; + } + Sprintf(outbuf, "%s %s %s", an(modif), bonus, inctyp); + return outbuf; +} + void enlightenment(final) int final; /* 0 => still in progress; 1 => over, survived; 2 => dead */ @@ -765,7 +836,7 @@ #ifdef ELBERETH if (u.uevent.uhand_of_elbereth) { - static const char *hofe_titles[3] = { + static const char * const hofe_titles[3] = { "the Hand of Elbereth", "the Envoy of Balance", "the Glory of Arioch" @@ -822,18 +893,6 @@ if (u.usick_type & SICK_NONVOMITABLE) you_are("sick from illness"); } - /* added by JDS */ - if (u.uhitinc) { - Sprintf(buf, "%s%i %s to hit", u.uhitinc > 0 ? "+" : "", - u.uhitinc, u.uhitinc > 0 ? "bonus" : "penalty"); - you_have(buf); - - } - if (u.udaminc) { - Sprintf(buf, "%s%i %s to damage", u.udaminc > 0 ? "+" : "", - u.udaminc, u.udaminc > 0 ? "bonus" : "penalty"); - you_have(buf); - } /* end JDS portion */ } if (Stoned) you_are("turning to stone"); if (Slimed) you_are("turning into slime"); @@ -881,7 +940,16 @@ if (u.umconf) you_are("going to confuse monsters"); /*** Appearance and behavior ***/ - if (Adornment) you_are("adorned"); + if (Adornment) { + int adorn = 0; + + if(uleft && uleft->otyp == RIN_ADORNMENT) adorn += uleft->spe; + if(uright && uright->otyp == RIN_ADORNMENT) adorn += uright->spe; + if (adorn < 0) + you_are("poorly adorned"); + else + 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 @@ -906,7 +974,10 @@ else if (Amphibious) you_can("breathe water"); if (Passes_walls) you_can("walk through walls"); #ifdef STEED - if (u.usteed) { + /* If you die while dismounting, u.usteed is still set. Since several + * places in the done() sequence depend on u.usteed, just detect this + * special case. */ + if (u.usteed && (final < 2 || strcmp(killer, "riding accident"))) { Sprintf(buf, "riding %s", y_monnam(u.usteed)); you_are(buf); } @@ -925,9 +996,25 @@ } /*** Physical attributes ***/ + if (u.uhitinc) + you_have(enlght_combatinc("to hit", u.uhitinc, final, buf)); + if (u.udaminc) + you_have(enlght_combatinc("damage", u.udaminc, final, buf)); if (Slow_digestion) you_have("slower digestion"); if (Regeneration) enl_msg("You regenerate", "", "d", ""); - if (u.uspellprot || Protection) you_are("protected"); + if (u.uspellprot || Protection) { + int prot = 0; + + if(uleft && uleft->otyp == RIN_PROTECTION) prot += uleft->spe; + if(uright && uright->otyp == RIN_PROTECTION) prot += uright->spe; + if (HProtection & INTRINSIC) prot += u.ublessed; + prot += u.uspellprot; + + if (prot < 0) + you_are("ineffectively protected"); + else + you_are("protected"); + } if (Protection_from_shape_changers) you_are("protected from shape changers"); if (Polymorph) you_are("polymorphing"); @@ -937,7 +1024,7 @@ you_are(buf); } if (Upolyd) { - if (u.ulycn >= LOW_PM) Strcpy(buf, "in beast form"); + if (u.umonnum == u.ulycn) 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); @@ -1039,16 +1126,18 @@ /* * Courtesy function for non-debug, non-explorer mode players * to help refresh them about who/what they are. + * Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise. */ -STATIC_OVL void +STATIC_OVL boolean minimal_enlightenment() { winid tmpwin; menu_item *selected; anything any; + int genidx, n; char buf[BUFSZ], buf2[BUFSZ]; - static char fmtstr[] = "%-15s: %-12s"; - static char deity_fmtstr[] = "%-17s%s"; + static const char fmtstr[] = "%-15s: %-12s"; + static const char deity_fmtstr[] = "%-17s%s"; any.a_void = 0; buf[0] = buf2[0] = '\0'; @@ -1085,10 +1174,11 @@ (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); + /* don't want poly_gender() here; it forces `2' for non-humanoids */ + genidx = is_neuter(youmonst.data) ? 2 : flags.female; + Sprintf(buf, fmtstr, "gender", genders[genidx].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); - - if (Upolyd) { + if (Upolyd && (int)u.mfemale != genidx) { Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); } @@ -1105,7 +1195,7 @@ && 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); + Sprintf(buf, fmtstr, "Chaotic", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf2, deity_fmtstr, align_gname(A_NEUTRAL), @@ -1113,25 +1203,28 @@ && 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); + Sprintf(buf, fmtstr, "Neutral", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf2, deity_fmtstr, align_gname(A_LAWFUL), - (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_LAWFUL) ? " (s,c)" : + (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); + Sprintf(buf, fmtstr, "Lawful", 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); + n = select_menu(tmpwin, PICK_NONE, &selected); destroy_nhwindow(tmpwin); + return (n != -1); } STATIC_PTR int doattributes() { - minimal_enlightenment(); + if (!minimal_enlightenment()) + return 0; if (wizard || discover) enlightenment(0); return 0; @@ -1409,6 +1502,10 @@ {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, +#ifdef PORT_DEBUG + {(char *)0, (char *)0, donull, TRUE}, +#endif + {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, @@ -1423,9 +1520,13 @@ #if defined(WIZARD) static const struct ext_func_tab debug_extcmdlist[] = { {"levelchange", "change experience level", wiz_level_change, TRUE}, - {"light sources", "show mobile light sources", wiz_light_sources, TRUE}, - {"monpoly_control", "control monster polymorphs", wiz_mon_polycontrol, TRUE}, - {"poly", "polymorph self", wiz_polyself, TRUE}, + {"lightsources", "show mobile light sources", wiz_light_sources, TRUE}, + {"monpolycontrol", "control monster polymorphs", wiz_mon_polycontrol, TRUE}, + {"panic", "test panic routine (fatal to game)", wiz_panic, TRUE}, + {"polyself", "polymorph self", wiz_polyself, TRUE}, +#ifdef PORT_DEBUG + {"portdebug", "wizard port debug command", wiz_port_debug, TRUE}, +#endif {"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}, @@ -1466,9 +1567,9 @@ } -static const char *template = "%-18s %4ld %6ld"; -static const char *count_str = " count bytes"; -static const char *separator = "------------------ ----- ------"; +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) @@ -1661,6 +1762,7 @@ boolean do_walk, do_rush, prefix_seen, bad_command, firsttime = (cmd == 0); + iflags.menu_requested = FALSE; if (firsttime) { flags.nopick = 0; cmd = parse(); @@ -1738,12 +1840,16 @@ multi = 0; return; case CMD_TRAVEL: - flags.travel = 1; - flags.run = 8; - flags.nopick = 1; - do_rush = TRUE; - break; + if (iflags.travelcmd) { + flags.travel = 1; + flags.run = 8; + flags.nopick = 1; + do_rush = TRUE; + break; + } + /*FALLTHRU*/ default: if (movecmd(*cmd)) { /* ordinary movement */ + flags.run = 0; /* only matters here if it was 8 */ do_walk = TRUE; } else if (movecmd(iflags.num_pad ? unmeta(*cmd) : lowc(*cmd))) { @@ -1755,6 +1861,14 @@ } break; } + + /* some special prefix handling */ + /* overload 'm' prefix for ',' to mean "request a menu" */ + if (prefix_seen && cmd[1] == ',') { + iflags.menu_requested = TRUE; + ++cmd; + } + if (do_walk) { if (multi) flags.mv = TRUE; domove(); @@ -1820,7 +1934,9 @@ } } *cp = '\0'; - Norep("Unknown command '%s'.", expcmd); + if (!prefix_seen || !iflags.cmdassist || + !help_dir(0, "Invalid direction key!")) + Norep("Unknown command '%s'.", expcmd); } /* didn't move */ flags.move = FALSE; @@ -1870,6 +1986,38 @@ return !u.dz; } +/* + * uses getdir() but unlike getdir() it specifically + * produces coordinates using the direction from getdir() + * and verifies that those coordinates are ok. + * + * If the call to getdir() returns 0, Never_mind is displayed. + * If the resulting coordinates are not okay, emsg is displayed. + * + * Returns non-zero if coordinates in cc are valid. + */ +int get_adjacent_loc(prompt,emsg,x,y,cc) +const char *prompt, *emsg; +xchar x,y; +coord *cc; +{ + xchar new_x, new_y; + if (!getdir(prompt)) { + pline(Never_mind); + return 0; + } + new_x = x + u.dx; + new_y = y + u.dy; + if (cc && isok(new_x,new_y)) { + cc->x = new_x; + cc->y = new_y; + } else { + if (emsg) pline(emsg); + return 0; + } + return 1; +} + int getdir(s) const char *s; @@ -1881,7 +2029,7 @@ dirsym = readchar(); else #endif - dirsym = yn_function (s ? s : "In what direction?", + dirsym = yn_function ((s && *s != '^') ? s : "In what direction?", (char *)0, '\0'); #ifdef REDO savech(dirsym); @@ -1889,14 +2037,86 @@ 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!"); + boolean did_help = FALSE; + if(!index(quitchars, dirsym)) { + if (iflags.cmdassist) { + did_help = help_dir((s && *s == '^') ? dirsym : 0, + "Invalid direction key!"); + } + if (!did_help) pline("What a strange direction!"); + } return 0; } if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir(); return 1; } +STATIC_OVL boolean +help_dir(sym, msg) +char sym; +const char *msg; +{ + char ctrl; + winid win; + static const char wiz_only_list[] = "EFGIOVW"; + char buf[BUFSZ], buf2[BUFSZ], *expl; + + win = create_nhwindow(NHW_TEXT); + if (!win) return FALSE; + if (msg) { + Sprintf(buf, "cmdassist: %s", msg); + putstr(win, 0, buf); + putstr(win, 0, ""); + } + if (letter(sym)) { + sym = highc(sym); + ctrl = (sym - 'A') + 1; + if ((expl = dowhatdoes_core(ctrl, buf2)) + && (!index(wiz_only_list, sym) +#ifdef WIZARD + || wizard +#endif + )) { + Sprintf(buf, "Are you trying to use ^%c%s?", sym, + index(wiz_only_list, sym) ? "" : + " as specified in the Guidebook"); + putstr(win, 0, buf); + putstr(win, 0, ""); + putstr(win, 0, expl); + putstr(win, 0, ""); + putstr(win, 0, "To use that command, you press"); + Sprintf(buf, + "the key, and the <%c> key at the same time.", sym); + putstr(win, 0, buf); + putstr(win, 0, ""); + } + } + if (iflags.num_pad) { + putstr(win, 0, "Valid direction keys (with number_pad on) are:"); + putstr(win, 0, " 7 8 9"); + putstr(win, 0, " \\ | / "); + putstr(win, 0, " 4- . -6"); + putstr(win, 0, " / | \\ "); + putstr(win, 0, " 1 2 3"); + } else { + putstr(win, 0, "Valid direction keys are:"); + putstr(win, 0, " y k u"); + putstr(win, 0, " \\ | / "); + putstr(win, 0, " h- . -l"); + putstr(win, 0, " / | \\ "); + putstr(win, 0, " b j n"); + }; + putstr(win, 0, ""); + putstr(win, 0, " < up"); + putstr(win, 0, " > down"); + putstr(win, 0, " . direct at yourself"); + putstr(win, 0, ""); + putstr(win, 0, "(Suppress this message with !cmdassist in config file.)"); + display_nhwindow(win, FALSE); + destroy_nhwindow(win); + return TRUE; +} + #endif /* OVL1 */ #ifdef OVLB @@ -1936,62 +2156,81 @@ x -= u.ux; y -= u.uy; - if ( abs(x) <= 1 && abs(y) <= 1 ) { - x = sgn(x), y = sgn(y); - } else { - u.tx = u.ux+x; - u.ty = u.uy+y; - cmd[0] = CMD_TRAVEL; - return cmd; - } + if (iflags.travelcmd) { + if (abs(x) <= 1 && abs(y) <= 1 ) { + x = sgn(x), y = sgn(y); + } else { + u.tx = u.ux+x; + u.ty = u.uy+y; + cmd[0] = CMD_TRAVEL; + return cmd; + } - if(x == 0 && y == 0) { - /* here */ - if(IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) { - cmd[0]=mod == CLICK_1 ? 'q' : M('d'); - return cmd; - } else if(IS_THRONE(levl[u.ux][u.uy].typ)) { - cmd[0]=M('s'); - return cmd; - } else if((u.ux == xupstair && u.uy == yupstair) - || (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up) - || (u.ux == xupladder && u.uy == yupladder)) { - return "<"; - } else if((u.ux == xdnstair && u.uy == ydnstair) - || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up) - || (u.ux == xdnladder && u.uy == ydnladder)) { - return ">"; - } else if(OBJ_AT(u.ux, u.uy)) { - cmd[0] = Is_container(level.objects[u.ux][u.uy]) ? M('l') : ','; - return cmd; - } else { - return "."; /* just rest */ - } - } + if(x == 0 && y == 0) { + /* here */ + if(IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) { + cmd[0]=mod == CLICK_1 ? 'q' : M('d'); + return cmd; + } else if(IS_THRONE(levl[u.ux][u.uy].typ)) { + cmd[0]=M('s'); + return cmd; + } else if((u.ux == xupstair && u.uy == yupstair) + || (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up) + || (u.ux == xupladder && u.uy == yupladder)) { + return "<"; + } else if((u.ux == xdnstair && u.uy == ydnstair) + || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up) + || (u.ux == xdnladder && u.uy == ydnladder)) { + return ">"; + } else if(OBJ_AT(u.ux, u.uy)) { + cmd[0] = Is_container(level.objects[u.ux][u.uy]) ? M('l') : ','; + return cmd; + } else { + return "."; /* just rest */ + } + } - /* directional commands */ + /* directional commands */ - dir = xytod(x, y); + dir = xytod(x, y); - if (!m_at(u.ux+x, u.uy+y) && !test_move(u.ux, u.uy, x, y, 1)) { - cmd[1] = (iflags.num_pad ? ndir[dir] : sdir[dir]); - cmd[2] = 0; - if (IS_DOOR(levl[u.ux+x][u.uy+y].typ)) { - /* slight assistance to the player: choose kick/open for them */ - if (levl[u.ux+x][u.uy+y].doormask & D_LOCKED) { - cmd[0] = C('d'); - return cmd; - } - if (levl[u.ux+x][u.uy+y].doormask & D_CLOSED) { - cmd[0] = 'o'; - return cmd; - } - } - if (levl[u.ux+x][u.uy+y].typ <= SCORR) { - cmd[0] = 's'; - cmd[1] = 0; - return cmd; - } + if (!m_at(u.ux+x, u.uy+y) && !test_move(u.ux, u.uy, x, y, TEST_MOVE)) { + cmd[1] = (iflags.num_pad ? ndir[dir] : sdir[dir]); + cmd[2] = 0; + if (IS_DOOR(levl[u.ux+x][u.uy+y].typ)) { + /* slight assistance to the player: choose kick/open for them */ + if (levl[u.ux+x][u.uy+y].doormask & D_LOCKED) { + cmd[0] = C('d'); + return cmd; + } + if (levl[u.ux+x][u.uy+y].doormask & D_CLOSED) { + cmd[0] = 'o'; + return cmd; + } + } + if (levl[u.ux+x][u.uy+y].typ <= SCORR) { + cmd[0] = 's'; + cmd[1] = 0; + return cmd; + } + } + } else { + /* 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 "."; + + dir = xytod(x, y); } /* move, attack, etc. */ @@ -2142,6 +2381,8 @@ /* Keyboard travel command */ static char cmd[2]; coord cc; + + if (!iflags.travelcmd) return 0; cmd[1]=0; cc.x = u.ux; cc.y = u.uy; @@ -2157,6 +2398,54 @@ return 0; } +#ifdef PORT_DEBUG +# ifdef WIN32CON +extern void NDECL(win32con_debug_keystrokes); +# endif + +int +wiz_port_debug() +{ + int n, k; + winid win; + anything any; + int item = 'a'; + int num_menu_selections; + struct menu_selection_struct { + char *menutext; + void NDECL((*fn)); + } menu_selections[] = { +#ifdef WIN32CON + {"test win32 keystrokes", win32con_debug_keystrokes}, +#endif + {(char *)0, (void NDECL((*)))0} /* array terminator */ + }; + + num_menu_selections = SIZE(menu_selections) - 1; + if (num_menu_selections > 0) { + menu_item *pick_list; + win = create_nhwindow(NHW_MENU); + start_menu(win); + for (k=0; k < num_menu_selections; ++k) { + any.a_int = k+1; + add_menu(win, NO_GLYPH, &any, item++, 0, ATR_NONE, + menu_selections[k].menutext, MENU_UNSELECTED); + } + end_menu(win, "Which port debugging feature?"); + n = select_menu(win, PICK_ONE, &pick_list); + destroy_nhwindow(win); + if (n > 0) { + n = pick_list[0].item.a_int - 1; + free((genericptr_t) pick_list); + /* execute the function */ + (*menu_selections[n].fn)(); + } + } else + pline("No port-specific debug capability defined."); + return 0; +} +# endif /*PORT_DEBUG*/ + #endif /* OVL0 */ /*cmd.c*/ diff -Naurd ../nethack-3.4.0/src/dbridge.c ./src/dbridge.c --- ../nethack-3.4.0/src/dbridge.c Wed Mar 20 23:43:01 2002 +++ ./src/dbridge.c Mon Feb 24 15:25:05 2003 @@ -400,7 +400,7 @@ if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) { pline("A %s force teleports you away...", Hallucination ? "normal" : "strange"); - teleds(xy.x, xy.y); + teleds(xy.x, xy.y, FALSE); } /* otherwise on top of the drawbridge is the * only viable spot in the dungeon, so stay there @@ -531,6 +531,7 @@ pline_The("%s passes through %s!", at_portcullis ? "portcullis" : "drawbridge", e_nam(etmp)); + if (is_u(etmp)) spoteffects(FALSE); return; } if (e_missed(etmp, FALSE)) { diff -Naurd ../nethack-3.4.0/src/decl.c ./src/decl.c --- ../nethack-3.4.0/src/decl.c Wed Mar 20 23:43:01 2002 +++ ./src/decl.c Mon Feb 24 15:25:05 2003 @@ -261,14 +263,14 @@ struct tc_gbl_data tc_gbl_data = { 0,0, 0,0 }; /* AS,AE, LI,CO */ char *fqn_prefix[PREFIX_COUNT] = { (char *)0, (char *)0, (char *)0, (char *)0, - (char *)0, (char *)0, (char *)0, (char *)0 }; + (char *)0, (char *)0, (char *)0, (char *)0, (char *)0 }; #ifdef PREFIXES_IN_USE char *fqn_prefix_names[PREFIX_COUNT] = { "hackdir", "leveldir", "savedir", "bonesdir", "datadir", "scoredir", - "lockdir", "configdir" }; + "lockdir", "configdir", "troubledir" }; #endif - + /* dummy routine used to force linkage */ void decl_init() diff -Naurd ../nethack-3.4.0/src/detect.c ./src/detect.c --- ../nethack-3.4.0/src/detect.c Wed Mar 20 23:43:01 2002 +++ ./src/detect.c Mon Feb 24 15:25:05 2003 @@ -115,7 +115,7 @@ /* didn't find it; perhaps a monster is carrying it */ #ifndef GOLDOBJ if ((mtmp = m_at(x,y)) != 0) { - if (oclass == GOLD_CLASS && mtmp->mgold) + if (oclass == COIN_CLASS && mtmp->mgold) return FALSE; else for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (o_in(otmp, oclass)) return FALSE; @@ -169,7 +169,7 @@ struct obj *temp; boolean stale; - known = stale = clear_stale_map(GOLD_CLASS, + known = stale = clear_stale_map(COIN_CLASS, (unsigned)(sobj->blessed ? GOLD : 0)); /* look for gold carried by monsters (might be in a container) */ @@ -186,7 +186,7 @@ if (sobj->blessed && o_material(obj, GOLD)) { known = TRUE; goto outgoldmap; - } else if (o_in(obj, GOLD_CLASS)) { + } else if (o_in(obj, COIN_CLASS)) { known = TRUE; goto outgoldmap; /* skip further searching */ } @@ -197,7 +197,7 @@ if (sobj->blessed && o_material(obj, GOLD)) { known = TRUE; if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap; - } else if (o_in(obj, GOLD_CLASS)) { + } else if (o_in(obj, COIN_CLASS)) { known = TRUE; if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap; } @@ -242,7 +242,7 @@ temp->oy = obj->oy; } map_object(temp,1); - } else if ((temp = o_in(obj, GOLD_CLASS))) { + } else if ((temp = o_in(obj, COIN_CLASS))) { if (temp != obj) { temp->ox = obj->ox; temp->oy = obj->oy; @@ -269,7 +269,7 @@ temp->oy = mtmp->my; map_object(temp,1); break; - } else if ((temp = o_in(obj, GOLD_CLASS))) { + } else if ((temp = o_in(obj, COIN_CLASS))) { temp->ox = mtmp->mx; temp->oy = mtmp->my; map_object(temp,1); @@ -391,7 +391,7 @@ } /* - * Used for scrolls, potions, and crystal balls. Returns: + * Used for scrolls, potions, spells, and crystal balls. Returns: * * 1 - nothing was detected * 0 - something was detected @@ -403,8 +403,9 @@ { register int x, y; int is_cursed = (detector && detector->cursed); - int do_dknown = - (detector && detector->oclass == POTION_CLASS && detector->blessed); + int do_dknown = (detector && (detector->oclass == POTION_CLASS || + detector->oclass == SPBOOK_CLASS) && + detector->blessed); int ct = 0, ctu = 0; register struct obj *obj, *otmp = (struct obj *)0; register struct monst *mtmp; @@ -448,9 +449,9 @@ if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT && (!class || class == objects[mtmp->mappearance].oc_class)) || #ifndef GOLDOBJ - (mtmp->mgold && (!class || class == GOLD_CLASS))) { + (mtmp->mgold && (!class || class == COIN_CLASS))) { #else - (findgold(mtmp->minvent) && (!class || class == GOLD_CLASS))) { + (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) { #endif ct++; break; @@ -530,9 +531,9 @@ temp.corpsenm = PM_TENGU; /* if mimicing a corpse */ map_object(&temp, 1); #ifndef GOLDOBJ - } else if (mtmp->mgold && (!class || class == GOLD_CLASS)) { + } else if (mtmp->mgold && (!class || class == COIN_CLASS)) { #else - } else if (findgold(mtmp->minvent) && (!class || class == GOLD_CLASS)) { + } else if (findgold(mtmp->minvent) && (!class || class == COIN_CLASS)) { #endif struct obj gold; @@ -753,7 +754,7 @@ else return "near you"; } -static struct { +static const struct { const char *what; d_level *where; } level_detects[] = { diff -Naurd ../nethack-3.4.0/src/dig.c ./src/dig.c --- ../nethack-3.4.0/src/dig.c Wed Mar 20 23:43:02 2002 +++ ./src/dig.c Mon Feb 24 15:25:05 2003 @@ -13,11 +13,19 @@ STATIC_DCL boolean NDECL(rm_waslit); STATIC_DCL void FDECL(mkcavepos, (XCHAR_P,XCHAR_P,int,BOOLEAN_P,BOOLEAN_P)); STATIC_DCL void FDECL(mkcavearea, (BOOLEAN_P)); -STATIC_DCL int FDECL(dig_typ, (XCHAR_P,XCHAR_P)); +STATIC_DCL int FDECL(dig_typ, (struct obj *,XCHAR_P,XCHAR_P)); STATIC_DCL int NDECL(dig); STATIC_DCL schar FDECL(fillholetyp, (int, int)); STATIC_DCL void NDECL(dig_up_grave); +/* Indices returned by dig_typ() */ +#define DIGTYP_UNDIGGABLE 0 +#define DIGTYP_ROCK 1 +#define DIGTYP_STATUE 2 +#define DIGTYP_BOULDER 3 +#define DIGTYP_DOOR 4 +#define DIGTYP_TREE 5 + STATIC_OVL boolean rm_waslit() @@ -122,16 +130,21 @@ } /* When digging into location , what are you actually digging into? */ -/* result: 1=>statue, 2=>boulder, 3=>door, 0=>other; used as array index */ -/* KMH -- Added 4=>tree */ STATIC_OVL int -dig_typ(x, y) +dig_typ(otmp, x, y) +struct obj *otmp; xchar x, y; { - return (sobj_at(STATUE, x, y) ? 1 : - sobj_at(BOULDER, x, y) ? 2 : - closed_door(x, y) ? 3 : - IS_TREE(levl[x][y].typ) ? 4: 0); + boolean ispick = is_pick(otmp); + + return (ispick && sobj_at(STATUE, x, y) ? DIGTYP_STATUE : + ispick && sobj_at(BOULDER, x, y) ? DIGTYP_BOULDER : + closed_door(x, y) ? DIGTYP_DOOR : + IS_TREE(levl[x][y].typ) ? + (ispick ? DIGTYP_UNDIGGABLE : DIGTYP_TREE) : + ispick && IS_ROCK(levl[x][y].typ) && + (!level.flags.arboreal || IS_WALL(levl[x][y].typ)) ? + DIGTYP_ROCK : DIGTYP_UNDIGGABLE); } boolean @@ -153,11 +166,12 @@ int x, y; { struct trap *ttmp = t_at(x, y); + const char *verb = (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in"; if (On_stairs(x, y)) { if (x == xdnladder || x == xupladder) { if(verbose) pline_The("ladder resists your effort."); - } else if(verbose) pline_The("stairs are too hard to dig in."); + } else if(verbose) pline_The("stairs are too hard to %s.", verb); return(FALSE); } else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) { if(verbose) pline_The("throne is too hard to break apart."); @@ -167,20 +181,20 @@ if(verbose) pline_The("altar is too hard to break apart."); return(FALSE); } else if (Is_airlevel(&u.uz)) { - if(verbose) You("cannot dig in thin air."); + if(verbose) You("cannot %s thin air.", verb); return(FALSE); } else if (Is_waterlevel(&u.uz)) { if(verbose) pline_The("water splashes and subsides."); return(FALSE); - } else if ((IS_WALL(levl[x][y].typ) && + } else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR && (levl[x][y].wall_info & W_NONDIGGABLE) != 0) || (ttmp && (ttmp->ttyp == MAGIC_PORTAL || !Can_dig_down(&u.uz)))) { - if(verbose) pline_The("%s here is too hard to dig in.", - surface(x,y)); + if(verbose) pline_The("%s here is too hard to %s.", + surface(x,y), verb); return(FALSE); } else if (sobj_at(BOULDER, x, y)) { - if(verbose) There("isn't enough room to dig here."); + if(verbose) There("isn't enough room to %s here.", verb); return(FALSE); } else if (madeby == BY_OBJECT && /* the block against existing traps is mainly to @@ -197,11 +211,14 @@ { register struct rm *lev; register xchar dpx = digging.pos.x, dpy = digging.pos.y; + register boolean ispick = uwep && is_pick(uwep); + const char *verb = + (!uwep || is_pick(uwep)) ? "dig into" : "chop through"; lev = &levl[dpx][dpy]; /* perhaps a nymph stole your pick-axe while you were busy digging */ /* or perhaps you teleported away */ - if (u.uswallow || !uwep || !is_pick(uwep) || + if (u.uswallow || !uwep || (!ispick && !is_axe(uwep)) || !on_level(&digging.level, &u.uz) || ((digging.down ? (dpx != u.ux || dpy != u.uy) : (distu(dpx,dpy) > 2)))) @@ -210,12 +227,14 @@ if (digging.down) { if(!dig_check(BY_YOU, TRUE, u.ux, u.uy)) return(0); } else { /* !digging.down */ - if (IS_ROCK(lev->typ) && !may_dig(dpx,dpy) && !dig_typ(dpx, dpy)) { - pline("This wall is too hard to dig into."); + if (IS_TREE(lev->typ) && !may_dig(dpx,dpy) && + dig_typ(uwep, dpx, dpy) == DIGTYP_TREE) { + pline("This tree seems to be petrified."); return(0); } - if (IS_TREE(lev->typ) && !may_dig(dpx,dpy) && dig_typ(dpx, dpy) == 4) { - pline("This tree seems to be petrified."); + if (IS_ROCK(lev->typ) && !may_dig(dpx,dpy) && + dig_typ(uwep, dpx, dpy) == DIGTYP_ROCK) { + pline("This wall is too hard to %s.", verb); return(0); } } @@ -319,6 +338,7 @@ if (IS_TREE(lev->typ)) { digtxt = "You cut down the tree."; lev->typ = ROOM; + if (!rn2(5)) (void) rnd_treefruit_at(dpx, dpy); } else { digtxt = "You succeed in cutting away some rock."; lev->typ = CORR; @@ -330,7 +350,8 @@ } if (level.flags.is_maze_lev) { lev->typ = ROOM; - } else if (level.flags.is_cavernous_lev) { + } else if (level.flags.is_cavernous_lev && + !in_town(dpx, dpy)) { lev->typ = CORR; } else { lev->typ = DOOR; @@ -360,7 +381,7 @@ newsym(dpx, dpy); if(digtxt && !digging.quiet) pline(digtxt); /* after newsym */ if(dmgtxt) - pay_for_damage(dmgtxt); + pay_for_damage(dmgtxt, FALSE); if(Is_earthlevel(&u.uz) && !rn2(3)) { register struct monst *mtmp; @@ -389,19 +410,19 @@ digging.level.dlevel = -1; return(0); } else { /* not enough effort has been spent yet */ - static const char *d_target[5] = { - "rock", "statue", "boulder", "door", "tree" + static const char *const d_target[6] = { + "", "rock", "statue", "boulder", "door", "tree" }; - int dig_target = dig_typ(dpx, dpy); + int dig_target = dig_typ(uwep, dpx, dpy); - if (IS_WALL(lev->typ) || dig_target == 3) { + if (IS_WALL(lev->typ) || dig_target == DIGTYP_DOOR) { if(*in_rooms(dpx, dpy, SHOPBASE)) { - pline("This %s seems too hard to dig into.", - IS_DOOR(lev->typ) ? "door" : "wall"); + pline("This %s seems too hard to %s.", + IS_DOOR(lev->typ) ? "door" : "wall", verb); return(0); } - } else if (!IS_ROCK(lev->typ) && !dig_target) - return(0); /* statue or boulder got taken */ + } else if (!IS_ROCK(lev->typ) && dig_target == DIGTYP_ROCK) + return(0); /* statue or boulder got taken */ if(!did_dig_msg) { You("hit the %s with all your might.", d_target[dig_target]); @@ -475,7 +496,7 @@ breaking bypasses that routine and calls us directly */ if (IS_FOUNTAIN(lev->typ)) { dogushforth(FALSE); - lev->looted |= F_WARNED; /* force dryup */ + SET_FOUNTAIN_WARNED(x,y); /* force dryup */ dryup(x, y, madeby_u); return; #ifdef SINKS @@ -483,6 +504,13 @@ breaksink(x, y); return; #endif + } else if (lev->typ == DRAWBRIDGE_DOWN || + (is_drawbridge_wall(x, y) >= 0)) { + int bx = x, by = y; + /* if under the portcullis, the bridge is adjacent */ + (void) find_drawbridge(&bx, &by); + destroy_drawbridge(bx, by); + return; } if (ttyp != PIT && !Can_dig_down(&u.uz)) { @@ -510,7 +538,7 @@ if(madeby_u) { You("dig a pit in the %s.", surface_type); - if (shopdoor) pay_for_damage("ruin"); + if (shopdoor) pay_for_damage("ruin", FALSE); } else if (!madeby_obj && canseemon(madeby)) pline("%s digs a pit in the %s.", Monnam(madeby), surface_type); else if (cansee(x, y) && flags.verbose) @@ -559,13 +587,15 @@ impact_drop((struct obj *)0, x, y, 0); if (oldobjs != newobjs) (void) pickup(1); - if (shopdoor && madeby_u) pay_for_damage("ruin"); + if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE); } else { d_level newlevel; if (*u.ushops && madeby_u) shopdig(1); /* shk might snatch pack */ + /* handle earlier damage, eg breaking wand of digging */ + else if (!madeby_u) pay_for_damage("dig into", TRUE); You("fall through..."); /* Earlier checks must ensure that the destination @@ -578,7 +608,7 @@ spoteffects(FALSE); } } else { - if (shopdoor && madeby_u) pay_for_damage("ruin"); + if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE); if (newobjs) impact_drop((struct obj *)0, x, y, 0); if (mtmp) { @@ -602,6 +632,7 @@ } else { get_level(&tolevel, depth(&u.uz) + 1); } + if (mtmp->isshk) make_angry_shk(mtmp, 0, 0); migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, (coord *)0); } @@ -622,7 +653,8 @@ boolean nohole = !Can_dig_down(&u.uz); if ((ttmp && (ttmp->ttyp == MAGIC_PORTAL || nohole)) || - (IS_WALL(lev->typ) && (lev->wall_info & W_NONDIGGABLE) != 0)) { + (IS_ROCK(lev->typ) && lev->typ != SDOOR && + (lev->wall_info & W_NONDIGGABLE) != 0)) { pline_The("%s here is too hard to dig in.", surface(u.ux,u.uy)); } else if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) { @@ -731,7 +763,6 @@ { struct obj *otmp; - /* Grave-robbing is frowned upon... */ exercise(A_WIS, FALSE); if (Role_if(PM_ARCHEOLOGIST)) { @@ -777,23 +808,29 @@ use_pick_axe(obj) struct obj *obj; { + boolean ispick; char dirsyms[12]; char qbuf[QBUFSZ]; register char *dsp = dirsyms; register int rx, ry; int res = 0; - register const char *sdp; + register const char *sdp, *verb; + if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */ + /* Check tool */ if (obj != uwep) { - if (!wield_tool(obj)) return(0); + if (!wield_tool(obj, "swing")) return 0; else res = 1; } + ispick = is_pick(obj); + verb = ispick ? "dig" : "chop"; + if (u.utrap && u.utraptype == TT_WEB) { - pline("%s you can't dig while entangled in a web.", + pline("%s you can't %s while entangled in a web.", /* res==0 => no prior message; res==1 => just got "You now wield a pick-axe." message */ - !res ? "Unfortunately," : "But"); + !res ? "Unfortunately," : "But", verb); return res; } @@ -801,13 +838,15 @@ (void) movecmd(*sdp); /* sets u.dx and u.dy and u.dz */ rx = u.ux + u.dx; ry = u.uy + u.dy; - if(u.dz > 0 || (u.dz == 0 && isok(rx, ry) && - (IS_ROCK(levl[rx][ry].typ) || dig_typ(rx, ry)))) + /* Include down even with axe, so we have at least one direction */ + if (u.dz > 0 || + (u.dz == 0 && isok(rx, ry) && + dig_typ(obj, rx, ry) != DIGTYP_UNDIGGABLE)) *dsp++ = *sdp; sdp++; } *dsp = 0; - Sprintf(qbuf, "In what direction do you want to dig? [%s]", dirsyms); + Sprintf(qbuf, "In what direction do you want to %s? [%s]", verb, dirsyms); if(!getdir(qbuf)) return(res); @@ -825,11 +864,13 @@ register int rx, ry; register struct rm *lev; int dig_target; + boolean ispick = is_pick(obj); + const char *verbing = ispick ? "digging" : "chopping"; if (u.uswallow && attack(u.ustuck)) { ; /* return(1) */ } else if (Underwater) { - pline("Turbulence torpedoes your digging attempts."); + pline("Turbulence torpedoes your %s attempts.", verbing); } else if(u.dz < 0) { if(Levitation) You("don't have enough leverage."); @@ -858,8 +899,8 @@ lev = &levl[rx][ry]; if(MON_AT(rx, ry) && attack(m_at(rx, ry))) return(1); - dig_target = dig_typ(rx, ry); - if (!IS_ROCK(lev->typ) && !dig_target) { + dig_target = dig_typ(obj, rx, ry); + if (dig_target == DIGTYP_UNDIGGABLE) { /* ACCESSIBLE or POOL */ struct trap *trap = t_at(rx, ry); @@ -874,11 +915,27 @@ /* (maybe `move_into_trap()' would be better) */ nomul(-d(2,2)); nomovemsg = "You pull free."; - } else + } else if (lev->typ == IRONBARS) { + pline("Clang!"); + wake_nearby(); + } else if (IS_TREE(lev->typ)) + You("need an axe to cut down a tree."); + else if (IS_ROCK(lev->typ)) + You("need a pick to dig rock."); + else if (!ispick && (sobj_at(STATUE, rx, ry) || + sobj_at(BOULDER, rx, ry))) { + boolean vibrate = !rn2(3); + pline("Sparks fly as you whack the %s.%s", + sobj_at(STATUE, rx, ry) ? "statue" : "boulder", + vibrate ? " The axe-handle vibrates violently!" : ""); + if (vibrate) losehp(2, "axing a hard object", KILLED_BY); + } + else You("swing your %s through thin air.", aobjnam(obj, (char *)0)); } else { - static const char *d_action[5] = { + static const char * const d_action[6] = { + "swinging", "digging", "chipping the statue", "hitting the boulder", @@ -889,7 +946,8 @@ digging.quiet = FALSE; if (digging.pos.x != rx || digging.pos.y != ry || !on_level(&digging.level, &u.uz) || digging.down) { - if (flags.autodig && !dig_target && !digging.down && + if (flags.autodig && + dig_target == DIGTYP_ROCK && !digging.down && digging.pos.x == u.ux && digging.pos.y == u.uy && (moves <= digging.lastdigtime+2 && @@ -911,7 +969,7 @@ d_action[dig_target]); digging.chew = FALSE; } - set_occupation(dig, "digging", 0); + set_occupation(dig, verbing, 0); } } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) { /* it must be air -- water checked above */ @@ -922,6 +980,10 @@ /* Monsters which swim also happen not to be able to dig */ You("cannot stay under%s long enough.", is_pool(u.ux, u.uy) ? "water" : " the lava"); + } else if (!ispick) { + Your("%s merely scratches the %s.", + aobjnam(obj, (char *)0), surface(u.ux,u.uy)); + u_wipe_engr(3); } else { if (digging.pos.x != u.ux || digging.pos.y != u.uy || !on_level(&digging.level, &u.uz) || !digging.down) { @@ -932,18 +994,18 @@ digging.pos.y = u.uy; assign_level(&digging.level, &u.uz); digging.effort = 0; - You("start digging downward."); + You("start %s downward.", verbing); if (*u.ushops) shopdig(0); } else - You("continue digging downward."); + You("continue %s downward.", verbing); did_dig_msg = FALSE; - set_occupation(dig, "digging", 0); + set_occupation(dig, verbing, 0); } return(1); } /* - * Town Watchmen frown on damage to the town walls or fountains. + * Town Watchmen frown on damage to the town walls, trees or fountains. * It's OK to dig holes in the ground, however. * If mtmp is assumed to be a watchman, a watchman is found if mtmp == 0 * zap == TRUE if wand/spell of digging, FALSE otherwise (chewing) @@ -954,12 +1016,11 @@ xchar x, y; boolean zap; { - s_level *slev = Is_special(&u.uz); struct rm *lev = &levl[x][y]; - if (slev && slev->flags.town && + if (in_town(x, y) && (closed_door(x, y) || lev->typ == SDOOR || - IS_WALL(lev->typ) || IS_FOUNTAIN(lev->typ))) { + IS_WALL(lev->typ) || IS_FOUNTAIN(lev->typ) || IS_TREE(lev->typ))) { if (!mtmp) { for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; @@ -976,10 +1037,13 @@ verbalize("Halt, vandal! You're under arrest!"); (void) angry_guards(!(flags.soundok)); } else { - char *str; + const char *str; + if (IS_DOOR(lev->typ)) str = "door"; - else if (IS_WALL(lev->typ)) + else if (IS_TREE(lev->typ)) + str = "tree"; + else if (IS_ROCK(lev->typ)) str = "wall"; else str = "fountain"; @@ -1006,9 +1070,6 @@ here = &levl[mtmp->mx][mtmp->my]; if (here->typ == SDOOR) cvt_sdoor_to_door(here); /* ->typ = DOOR */ - if (IS_TREE(here->typ)) - /* KMH -- Trees shouldn't create piles */ - pile = 0; /* Eats away door if present & closed or locked */ if (closed_door(mtmp->mx, mtmp->my)) { @@ -1028,11 +1089,10 @@ } newsym(mtmp->mx, mtmp->my); return FALSE; - } else - if (!IS_ROCK(here->typ)) /* no dig */ + } else if (!IS_ROCK(here->typ) && !IS_TREE(here->typ)) /* no dig */ return FALSE; - /* Only rock and walls fall through to this point. */ + /* Only rock, trees, and walls fall through to this point. */ if ((here->wall_info & W_NONDIGGABLE) != 0) { impossible("mdig_tunnel: %s at (%d,%d) is undiggable", (IS_WALL(here->typ) ? "wall" : "stone"), @@ -1048,19 +1108,23 @@ add_damage(mtmp->mx, mtmp->my, 0L); if (level.flags.is_maze_lev) { here->typ = ROOM; - } else if (level.flags.is_cavernous_lev) { + } else if (level.flags.is_cavernous_lev && + !in_town(mtmp->mx, mtmp->my)) { here->typ = CORR; } else { here->typ = DOOR; here->doormask = D_NODOOR; } - } else - /* KMH -- Added support for trees */ - here->typ = level.flags.arboreal ? ROOM : CORR; - - if (pile && pile < 5) /* leave behind some rocks? */ - (void) mksobj_at((pile == 1) ? BOULDER : ROCK, + } else if (IS_TREE(here->typ)) { + here->typ = ROOM; + if (pile && pile < 5) + (void) rnd_treefruit_at(mtmp->mx, mtmp->my); + } else { + here->typ = CORR; + if (pile && pile < 5) + (void) mksobj_at((pile == 1) ? BOULDER : ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); + } newsym(mtmp->mx, mtmp->my); if (!sobj_at(BOULDER, mtmp->mx, mtmp->my)) unblock_point(mtmp->mx, mtmp->my); /* vision */ @@ -1165,6 +1229,13 @@ } else if (!Blind) pline_The("wall glows then fades."); break; + } else if (IS_TREE(room->typ)) { /* check trees before stone */ + if (!(room->wall_info & W_NONDIGGABLE)) { + room->typ = ROOM; + unblock_point(zx,zy); /* vision */ + } else if (!Blind) + pline_The("tree shudders but is unharmed."); + break; } else if (room->typ == STONE || room->typ == SCORR) { if (!(room->wall_info & W_NONDIGGABLE)) { room->typ = CORR; @@ -1181,13 +1252,16 @@ shopwall = TRUE; } watch_dig((struct monst *)0, zx, zy, TRUE); - if (level.flags.is_cavernous_lev) { + if (level.flags.is_cavernous_lev && !in_town(zx, zy)) { room->typ = CORR; } else { room->typ = DOOR; room->doormask = D_NODOOR; } digdepth -= 2; + } else if (IS_TREE(room->typ)) { + room->typ = ROOM; + digdepth -= 2; } else { /* IS_ROCK but not IS_WALL or SDOOR */ room->typ = CORR; digdepth--; @@ -1199,7 +1273,7 @@ } /* while */ tmp_at(DISP_END,0); /* closing call */ if (shopdoor || shopwall) - pay_for_damage(shopdoor ? "destroy" : "dig into"); + pay_for_damage(shopdoor ? "destroy" : "dig into", FALSE); return; } @@ -1477,7 +1551,7 @@ #endif #ifdef DEBUG -void +int wiz_debug_cmd() /* in this case, bury everything at your loc and around */ { int x, y; @@ -1485,6 +1559,7 @@ for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) if (isok(x,y)) bury_objs(x,y); + return 0; } #endif /* DEBUG */ diff -Naurd ../nethack-3.4.0/src/display.c ./src/display.c --- ../nethack-3.4.0/src/display.c Wed Mar 20 23:43:02 2002 +++ ./src/display.c Mon Feb 24 15:25:05 2003 @@ -331,7 +331,8 @@ map_background(x,y,show); \ } -void map_location(x,y,show) +void +map_location(x,y,show) int x, y, show; { _map_location(x,y,show); @@ -370,7 +371,7 @@ * the mimic was mimicing. */ - if (mon_mimic && sightflags) { + if (mon_mimic && (sightflags == PHYSICALLY_SEEN)) { switch (mon->m_ap_type) { default: impossible("display_monster: bad m_ap_type value [ = %d ]", @@ -459,6 +460,9 @@ if (mon_warning(mon)) { if (wl > WARNCOUNT - 1) wl = WARNCOUNT - 1; + /* 3.4.1: this really ought to be rn2(WARNCOUNT), but value "0" + isn't handled correctly by the what_is routine so avoid it */ + if (Hallucination) wl = rn1(WARNCOUNT-1,1); glyph = warning_to_glyph(wl); } else if (MATCH_WARN_OF_MON(mon)) { glyph = mon_to_glyph(mon); @@ -536,6 +540,13 @@ * underneath if already seen. Otherwise, show the appropriate * floor symbol. * + * Similarly, if the hero digs a hole in a wall or feels a location + * that used to contain an unseen monster. In these cases, + * there's no reason to assume anything was underneath, so + * just show the appropriate floor symbol. If something was + * embedded in the wall, the glyph will probably already + * reflect that. Don't change the symbol in this case. + * * This isn't quite correct. If the boulder was on top of some * other objects they should be seen once the boulder is removed. * However, we have no way of knowing that what is there now @@ -551,6 +562,12 @@ cmap_to_glyph(S_stone); show_glyph(x,y,lev->glyph); } + } else if ((lev->glyph >= cmap_to_glyph(S_stone) && + lev->glyph < cmap_to_glyph(S_room)) || + glyph_is_invisible(levl[x][y].glyph)) { + lev->glyph = lev->waslit ? cmap_to_glyph(S_room) : + cmap_to_glyph(S_stone); + show_glyph(x,y,lev->glyph); } } else { /* We feel it (I think hallways are the only things left). */ @@ -653,7 +670,7 @@ return; } if (x == u.ux && y == u.uy) { - if (canseeself()) { + if (senseself()) { _map_location(x,y,0); /* map *under* self */ display_self(); } else @@ -695,7 +712,7 @@ if (x == u.ux && y == u.uy) { feel_location(u.ux, u.uy); /* forces an update */ - if (canseeself()) display_self(); + if (senseself()) display_self(); } else if ((mon = m_at(x,y)) && ((see_it = (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon) @@ -1046,11 +1063,17 @@ see_monsters() { register struct monst *mon; + for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; newsym(mon->mx,mon->my); if (mon->wormno) see_wsegs(mon); } +#ifdef STEED + /* when mounted, hero's location gets caught by monster loop */ + if (!u.usteed) +#endif + newsym(u.ux, u.uy); } /* @@ -1062,16 +1085,19 @@ set_mimic_blocking() { register struct monst *mon; - for (mon = fmon; mon; mon = mon->nmon) - if(!DEADMONSTER(mon) && mon->minvis && + + for (mon = fmon; mon; mon = mon->nmon) { + if (DEADMONSTER(mon)) continue; + if (mon->minvis && ((mon->m_ap_type == M_AP_FURNITURE && - (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor))|| + (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor)) || (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) { if(See_invisible) block_point(mon->mx, mon->my); else unblock_point(mon->mx, mon->my); } + } } /* @@ -1843,7 +1869,7 @@ t_warn(lev) struct rm *lev; { - static const char *warn_str = "wall_angle: %s: case %d: seenv = 0x%x"; + static const char warn_str[] = "wall_angle: %s: case %d: seenv = 0x%x"; const char *wname; if (lev->typ == TUWALL) wname = "tuwall"; diff -Naurd ../nethack-3.4.0/src/dlb.c ./src/dlb.c --- ../nethack-3.4.0/src/dlb.c Wed Mar 20 23:43:02 2002 +++ ./src/dlb.c Mon Feb 24 15:25:05 2003 @@ -9,6 +9,8 @@ #include #endif +#define DATAPREFIX 4 + #ifdef DLB /* * Data librarian. Present a STDIO-like interface to NetHack while @@ -29,7 +31,7 @@ } dlb_procs_t; /* without extern.h via hack.h, these haven't been declared for us */ -extern FILE *FDECL(fopen_datafile, (const char *,const char *,BOOLEAN_P)); +extern FILE *FDECL(fopen_datafile, (const char *,const char *,int)); #ifdef DLBLIB /* @@ -199,7 +201,7 @@ { boolean status = FALSE; - lp->fdata = fopen_datafile(lib_name, RDBMODE, FALSE); + lp->fdata = fopen_datafile(lib_name, RDBMODE, DATAPREFIX); if (lp->fdata) { if (readlibdir(lp)) { status = TRUE; @@ -460,7 +462,7 @@ dp = (dlb *) alloc(sizeof(dlb)); if (do_dlb_fopen(dp, name, mode)) dp->fp = (FILE *) 0; - else if ((fp = fopen_datafile(name, mode, FALSE)) != 0) + else if ((fp = fopen_datafile(name, mode, DATAPREFIX)) != 0) dp->fp = fp; else { /* can't find anything */ diff -Naurd ../nethack-3.4.0/src/do.c ./src/do.c --- ../nethack-3.4.0/src/do.c Wed Mar 20 23:43:02 2002 +++ ./src/do.c Mon Feb 24 15:25:05 2003 @@ -7,19 +7,6 @@ #include "hack.h" #include "lev.h" -#include -#ifdef _MSC_VER /* MSC 6.0 defines errno quite differently */ -# if (_MSC_VER >= 600) -# define SKIP_ERRNO -# endif -#endif -#ifndef SKIP_ERRNO -#ifdef _DCC -const -#endif -extern int errno; -#endif - #ifdef SINKS # ifdef OVLB STATIC_DCL void FDECL(trycall, (struct obj *)); @@ -42,7 +29,7 @@ #ifdef OVLB static NEARDATA const char drop_types[] = - { ALLOW_COUNT, GOLD_CLASS, ALL_CLASSES, 0 }; + { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 }; /* 'd' command: drop one inventory item */ int @@ -85,13 +72,17 @@ fills_up = lava ? chance == 0 : chance != 0; if (fills_up) { + struct trap *ttmp = t_at(rx, ry); + if (ltyp == DRAWBRIDGE_UP) { levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */ levl[rx][ry].drawbridgemask |= DB_FLOOR; } else levl[rx][ry].typ = ROOM; + if (ttmp) (void) delfloortrap(ttmp); bury_objs(rx, ry); + newsym(rx,ry); if (pushing) { You("push %s into the %s.", the(xname(otmp)), what); @@ -206,6 +197,14 @@ } else if (is_lava(x, y)) { return fire_damage(obj, FALSE, FALSE, x, y); } else if (is_pool(x, y)) { + /* Reasonably bulky objects (arbitrary) splash when dropped. + * Stuff dropped near fountains always misses */ + if (Blind && flags.soundok && ((x == u.ux) && (y == u.uy)) && + weight(obj) > 9) { + pline("Splash!"); + map_background(x, y, 0); + newsym(x, y); + } water_damage(obj, FALSE, FALSE); } return FALSE; @@ -218,15 +217,15 @@ doaltarobj(obj) /* obj is an object dropped on an altar */ register struct obj *obj; { - if (Blind || obj->oclass == GOLD_CLASS) + if (Blind) return; /* KMH, conduct */ u.uconduct.gnostic++; - if (obj->blessed || obj->cursed) { + if ((obj->blessed || obj->cursed) && obj->oclass != COIN_CLASS) { There("is %s flash as %s %s the altar.", - an(hcolor(obj->blessed ? amber : Black)), + an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)), doname(obj), otense(obj, "hit")); if (!Hallucination) obj->bknown = 1; } else { @@ -273,7 +272,7 @@ pline_The("sink quivers upward for a moment."); break; case RIN_POISON_RESISTANCE: - You("smell rotten %s.", makeplural(pl_fruit)); + You("smell rotten %s.", makeplural(fruitname(FALSE))); break; case RIN_AGGRAVATE_MONSTER: pline("Several flies buzz angrily around the sink."); @@ -358,10 +357,10 @@ break; case RIN_PROTECTION: pline_The("sink glows %s for a moment.", - hcolor((obj->spe<0) ? Black : silver)); + hcolor((obj->spe<0) ? NH_BLACK : NH_SILVER)); break; case RIN_WARNING: - pline_The("sink glows %s for a moment.", hcolor(White)); + pline_The("sink glows %s for a moment.", hcolor(NH_WHITE)); break; case RIN_TELEPORTATION: pline_The("sink momentarily vanishes."); @@ -483,37 +482,41 @@ #endif if (!can_reach_floor()) { if(flags.verbose) You("drop %s.", doname(obj)); - if (obj->oclass != GOLD_CLASS || obj == invent) freeinv(obj); +#ifndef GOLDOBJ + if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj); +#else + /* Ensure update when we drop gold objects */ + if (obj->oclass == COIN_CLASS) flags.botl = 1; + freeinv(obj); +#endif hitfloor(obj); return(1); } - if (IS_ALTAR(levl[u.ux][u.uy].typ)) { - doaltarobj(obj); /* set bknown */ - } else - if(flags.verbose) You("drop %s.", doname(obj)); + if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose) + You("drop %s.", doname(obj)); } dropx(obj); return(1); } -/* Called in several places - should not produce texts */ -/* ship_object() _can_ produce texts--is that comment still correct? */ +/* Called in several places - may produce output */ +/* eg ship_object() and dropy() -> sellobj() both produce output */ void dropx(obj) register struct obj *obj; { #ifndef GOLDOBJ - if (obj->oclass != GOLD_CLASS || obj == invent) freeinv(obj); + if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj); #else /* Ensure update when we drop gold objects */ - if (obj->oclass == GOLD_CLASS) flags.botl = 1; - /* Money is usually not in our inventory */ - /*if (obj->oclass != GOLD_CLASS || obj == invent)*/ - /* !!!! make sure we don't drop "created" gold not in inventory any more,*/ - /* or this will crash !!!! */ + if (obj->oclass == COIN_CLASS) flags.botl = 1; freeinv(obj); #endif - if (!u.uswallow && ship_object(obj, u.ux, u.uy, FALSE)) return; + if (!u.uswallow) { + if (ship_object(obj, u.ux, u.uy, FALSE)) return; + if (IS_ALTAR(levl[u.ux][u.uy].typ)) + doaltarobj(obj); /* set bknown */ + } dropy(obj); } @@ -528,15 +531,39 @@ if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return; /* uswallow check done by GAN 01/29/87 */ if(u.uswallow) { - boolean could_petrify; + boolean could_petrify = FALSE; + boolean could_poly = FALSE; + boolean could_slime = FALSE; + boolean could_grow = FALSE; + boolean could_heal = FALSE; + if (obj != uball) { /* mon doesn't pick up ball */ - could_petrify = obj->otyp == CORPSE && - touch_petrifies(&mons[obj->corpsenm]); + if (obj->otyp == CORPSE) { + could_petrify = touch_petrifies(&mons[obj->corpsenm]); + could_poly = polyfodder(obj); + could_slime = (obj->corpsenm == PM_GREEN_SLIME); + could_grow = (obj->corpsenm == PM_WRAITH); + could_heal = (obj->corpsenm == PM_NURSE); + } (void) mpickobj(u.ustuck,obj); - if (could_petrify && is_animal(u.ustuck->data)) { - minstapetrify(u.ustuck, TRUE); - /* Don't leave a cockatrice corpse available in a statue */ - if (!u.uswallow) delobj(obj); + if (is_animal(u.ustuck->data)) { + if (could_poly || could_slime) { + (void) newcham(u.ustuck, + could_poly ? (struct permonst *)0 : + &mons[PM_GREEN_SLIME], + FALSE, could_slime); + delobj(obj); /* corpse is digested */ + } else if (could_petrify) { + minstapetrify(u.ustuck, TRUE); + /* Don't leave a cockatrice corpse in a statue */ + if (!u.uswallow) delobj(obj); + } else if (could_grow) { + (void) grow_up(u.ustuck, (struct monst *)0); + delobj(obj); /* corpse is digested */ + } else if (could_heal) { + u.ustuck->mhp = u.ustuck->mhpmax; + delobj(obj); /* corpse is digested */ + } } } } else { @@ -614,6 +641,7 @@ /* Hack: gold is not in the inventory, so make a gold object and put it at the head of the inventory list. */ u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */ + u_gold->in_use = TRUE; u.ugold = u_gold->quan; /* put the gold back */ assigninvlet(u_gold); /* might end up as NOINVSYM */ u_gold->nobj = invent; @@ -668,7 +696,7 @@ if (cnt < otmp->quan && !welded(otmp) && (!otmp->cursed || otmp->otyp != LOADSTONE)) { #ifndef GOLDOBJ - if (otmp->oclass == GOLD_CLASS) + if (otmp->oclass == COIN_CLASS) (void) splitobj(otmp, otmp->quan - cnt); else #endif @@ -682,10 +710,11 @@ drop_done: #ifndef GOLDOBJ - if (u_gold && invent && invent->oclass == GOLD_CLASS) { + if (u_gold && invent && invent->oclass == COIN_CLASS) { /* didn't drop [all of] it */ u_gold = invent; invent = u_gold->nobj; + u_gold->in_use = FALSE; dealloc_obj(u_gold); update_inventory(); } @@ -834,14 +863,14 @@ currentlevel_rewrite() { register int fd; + char whynot[BUFSZ]; /* since level change might be a bit slow, flush any buffered screen * output (like "you fall through a trap door") */ mark_synch(); - fd = create_levelfile(ledger_no(&u.uz)); - - if(fd < 0) { + fd = create_levelfile(ledger_no(&u.uz), whynot); + if (fd < 0) { /* * This is not quite impossible: e.g., we may have * exceeded our quota. If that is the case then we @@ -849,8 +878,7 @@ * Another possibility is that the directory was not * writable. */ - pline("Cannot create level file for level %d.", - ledger_no(&u.uz)); + pline("%s", whynot); return -1; } @@ -910,6 +938,7 @@ familiar = FALSE; boolean new = FALSE; /* made a new level? */ struct monst *mtmp; + char whynot[BUFSZ]; if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel)) newlevel->dlevel = dunlevs_in_dungeon(newlevel); @@ -953,7 +982,7 @@ pline("A mysterious force momentarily surrounds you..."); if (on_level(newlevel, &u.uz)) { - (void) safe_teleds(); + (void) safe_teleds(FALSE); (void) next_to_u(); return; } else @@ -983,6 +1012,7 @@ fill_pit(u.ux, u.uy); u.ustuck = 0; /* idem */ u.uinwater = 0; + u.uundetected = 0; /* not hidden, even if means are available */ keepdogs(FALSE); if (u.uswallow) /* idem */ u.uswldtim = u.uswallow = 0; @@ -1044,12 +1074,14 @@ new = TRUE; /* made the level */ } else { /* returning to previously visited level; reload it */ - fd = open_levelfile(new_ledger); + fd = open_levelfile(new_ledger, whynot); if (fd < 0) { - pline("Cannot open file (#%d) for level %d (errno %d).", - (int) new_ledger, depth(&u.uz), errno); + pline("%s", whynot); pline("Probably someone removed it."); + killer = whynot; done(TRICKED); + /* we'll reach here if running in wizard mode */ + error("Cannot continue this game."); } minit(); /* ZEROCOMP */ getlev(fd, hackpid, new_ledger, FALSE); @@ -1118,13 +1150,13 @@ freeinv(uball); } } - losehp(rnd(3), "falling downstairs", KILLED_BY); #ifdef STEED - if (u.usteed) { + /* falling off steed has its own losehp() call */ + if (u.usteed) dismount_steed(DISMOUNT_FELL); - if (Punished) unplacebc(); - } + else #endif + losehp(rnd(3), "falling downstairs", KILLED_BY); selftouch("Falling, you"); } else if (u.dz && at_ladder) You("climb down the ladder."); @@ -1228,13 +1260,13 @@ } if (familiar) { - static const char *fam_msgs[4] = { + static const char * const fam_msgs[4] = { "You have a sense of deja vu.", "You feel like you've been here before.", "This place %s familiar...", 0 /* no message */ }; - static const char *halu_fam_msgs[4] = { + static const char * const halu_fam_msgs[4] = { "Whoa! Everything %s different.", "You are surrounded by twisty little passages, all alike.", "Gee, this %s like uncle Conan's place...", @@ -1295,6 +1327,8 @@ save_currentstate(); #endif + /* assume this will always return TRUE when changing level */ + (void) in_out_region(u.ux, u.uy); (void) pickup(1); } diff -Naurd ../nethack-3.4.0/src/do_name.c ./src/do_name.c --- ../nethack-3.4.0/src/do_name.c Wed Mar 20 23:43:03 2002 +++ ./src/do_name.c Mon Feb 24 15:25:05 2003 @@ -49,7 +49,7 @@ int cx, cy, i, c; int sidx, tx, ty; boolean msg_given = TRUE; /* clear message window by default */ - static const char *pick_chars = ".,;:"; + static const char pick_chars[] = ".,;:"; const char *cp; const char *sdp; if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */ @@ -275,9 +275,10 @@ /* strip leading and trailing spaces; unnames monster if all spaces */ (void)mungspaces(buf); - if (mtmp->iswiz || type_is_pname(mtmp->data)) + if (mtmp->data->geno & G_UNIQ) pline("%s doesn't like being called names!", Monnam(mtmp)); - else (void) christen_monst(mtmp, buf); + else + (void) christen_monst(mtmp, buf); return(0); } @@ -361,8 +362,12 @@ } if (obj->owornmask) { + boolean save_twoweap = u.twoweap; + /* unwearing the old instance will clear dual-wield mode + if this object is either of the two weapons */ setworn((struct obj *)0, obj->owornmask); setworn(otmp, otmp->owornmask); + u.twoweap = save_twoweap; } /* replace obj with otmp */ @@ -421,7 +426,12 @@ (genericptr_t)obj->oextra, lth, name); } if (lth) artifact_exists(obj, name, TRUE); - if (obj->oartifact && obj == uswapwep) untwoweapon(); + if (obj->oartifact) { + /* can't dual-wield with artifact as secondary weapon */ + if (obj == uswapwep) untwoweapon(); + /* activate warning if you've just named your weapon "Sting" */ + if (obj == uwep) set_artifact_intrinsic(obj, TRUE, W_WEP); + } if (carried(obj)) update_inventory(); return obj; } @@ -460,6 +470,11 @@ #endif obj = getobj(callable, "call"); if (obj) { + /* behave as if examining it in inventory; + this might set dknown if it was picked up + while blind and the hero can now see */ + (void) xname(obj); + if (!obj->dknown) { You("would never recognize another one."); return 0; @@ -516,7 +531,7 @@ #endif /*OVLB*/ #ifdef OVL0 -static const char *ghostnames[] = { +static const char * const ghostnames[] = { /* these names should have length < PL_NSIZ */ /* Capitalize the names for aesthetics -dgk */ "Adri", "Andries", "Andreas", "Bert", "David", "Dirk", "Emile", @@ -703,13 +718,12 @@ name_at_start = (boolean)type_is_pname(mdat); } - if (name_at_start && !has_adjectives) { + if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) { if (mdat == &mons[PM_WIZARD_OF_YENDOR]) article = ARTICLE_THE; else article = ARTICLE_NONE; - } else if (mons[monsndx(mdat)].geno & G_UNIQ && - article == ARTICLE_A) { + } else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) { article = ARTICLE_THE; } @@ -804,8 +818,17 @@ y_monnam(mtmp) struct monst *mtmp; { - return x_monnam(mtmp, ARTICLE_YOUR, (char *)0, - mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE); + int prefix, suppression_flag; + + prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE; + suppression_flag = (mtmp->mnamelth +#ifdef STEED + /* "saddled" is redundant when mounted */ + || mtmp == u.usteed +#endif + ) ? SUPPRESS_SADDLE : 0; + + return x_monnam(mtmp, prefix, (char *)0, suppression_flag, FALSE); } #endif /* OVL0 */ @@ -862,7 +885,7 @@ return outbuf; } -static const char *bogusmons[] = { +static const char * const bogusmons[] = { "jumbo shrimp", "giant pigmy", "gnu", "killer penguin", "giant cockroach", "giant slug", "maggot", "pterodactyl", "tyrannosaurus rex", "basilisk", "beholder", "nightmare", @@ -959,7 +982,7 @@ #ifdef OVL2 -static NEARDATA const char *hcolors[] = { +static NEARDATA const char * const hcolors[] = { "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white", "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter", @@ -980,9 +1003,8 @@ } /* Aliases for road-runner nemesis - * See also http://www.geocities.com/EnchantedForest/1141/latin.html */ -static const char *coynames[] = { +static const char * const coynames[] = { "Carnivorous Vulgaris","Road-Runnerus Digestus", "Eatibus Anythingus" ,"Famishus-Famishus", "Eatibus Almost Anythingus","Eatius Birdius", @@ -996,7 +1018,8 @@ "Nemesis Riduclii","Canis latrans" }; -char *coyotename(mtmp, buf) +char * +coyotename(mtmp, buf) struct monst *mtmp; char *buf; { diff -Naurd ../nethack-3.4.0/src/do_wear.c ./src/do_wear.c --- ../nethack-3.4.0/src/do_wear.c Wed Mar 20 23:43:04 2002 +++ ./src/do_wear.c Mon Feb 24 15:25:05 2003 @@ -17,20 +17,20 @@ static NEARDATA const char see_yourself[] = "see yourself"; static NEARDATA const char unknown_type[] = "Unknown type of %s (%d)"; -static NEARDATA const char *c_armor = "armor", - *c_suit = "suit", +static NEARDATA const char c_armor[] = "armor", + c_suit[] = "suit", #ifdef TOURIST - *c_shirt = "shirt", + c_shirt[] = "shirt", #endif - *c_cloak = "cloak", - *c_gloves = "gloves", - *c_boots = "boots", - *c_helmet = "helmet", - *c_shield = "shield", - *c_weapon = "weapon", - *c_sword = "sword", - *c_axe = "axe", - *c_that_ = "that"; + c_cloak[] = "cloak", + c_gloves[] = "gloves", + c_boots[] = "boots", + c_helmet[] = "helmet", + c_shield[] = "shield", + c_weapon[] = "weapon", + c_sword[] = "sword", + c_axe[] = "axe", + c_that_[] = "that"; static NEARDATA const long takeoff_order[] = { WORN_BLINDF, W_WEP, WORN_SHIELD, WORN_GLOVES, LEFT_RING, RIGHT_RING, WORN_CLOAK, @@ -321,7 +321,7 @@ pline("%s for a moment.", Tobjnam(uarmh, "vibrate")); else pline("%s %s for a moment.", - Tobjnam(uarmh, "glow"), hcolor(Black)); + Tobjnam(uarmh, "glow"), hcolor(NH_BLACK)); curse(uarmh); } flags.botl = 1; /* reveal new alignment or INT & WIS */ @@ -635,7 +635,7 @@ register struct obj *obj; { long oldprop = u.uprops[objects[obj->otyp].oc_oprop].extrinsic; - int old_attrib; + int old_attrib, which; if (obj == uwep) setuwep((struct obj *) 0); if (obj == uswapwep) setuswapwep((struct obj *) 0); @@ -690,44 +690,31 @@ self_invis_message(); } break; - case RIN_ADORNMENT: - old_attrib = ACURR(A_CHA); - ABON(A_CHA) += obj->spe; - flags.botl = 1; - if (ACURR(A_CHA) != old_attrib || - (objects[RIN_ADORNMENT].oc_name_known && - old_attrib != 25 && old_attrib != 3)) { - makeknown(RIN_ADORNMENT); - obj->known = TRUE; - } - break; case RIN_LEVITATION: - if(!oldprop && !HLevitation) { - float_up(); - makeknown(RIN_LEVITATION); - obj->known = TRUE; - spoteffects(FALSE); /* for sinks */ + if (!oldprop && !HLevitation) { + float_up(); + makeknown(RIN_LEVITATION); + spoteffects(FALSE); /* for sinks */ } break; case RIN_GAIN_STRENGTH: - old_attrib = ACURR(A_STR); - ABON(A_STR) += obj->spe; - flags.botl = 1; - if (ACURR(A_STR) != old_attrib || - (objects[RIN_GAIN_STRENGTH].oc_name_known && - old_attrib != STR19(25) && old_attrib != 3)) { - makeknown(RIN_GAIN_STRENGTH); - obj->known = TRUE; - } - break; + which = A_STR; + goto adjust_attrib; case RIN_GAIN_CONSTITUTION: - old_attrib = ACURR(A_CON); - ABON(A_CON) += obj->spe; - flags.botl = 1; - if (ACURR(A_CON) != old_attrib || - objects[RIN_GAIN_CONSTITUTION].oc_name_known) { - makeknown(RIN_GAIN_CONSTITUTION); - obj->known = TRUE; + which = A_CON; + goto adjust_attrib; + case RIN_ADORNMENT: + which = A_CHA; + adjust_attrib: + old_attrib = ACURR(which); + ABON(which) += obj->spe; + if (ACURR(which) != old_attrib || + (objects[obj->otyp].oc_name_known && + old_attrib != 25 && old_attrib != 3)) { + flags.botl = 1; + makeknown(obj->otyp); + obj->known = 1; + update_inventory(); } break; case RIN_INCREASE_ACCURACY: /* KMH */ @@ -740,11 +727,11 @@ rescham(); break; case RIN_PROTECTION: - flags.botl = 1; if (obj->spe || objects[RIN_PROTECTION].oc_name_known) { - makeknown(RIN_PROTECTION); - obj->known = TRUE; - update_inventory(); + flags.botl = 1; + makeknown(RIN_PROTECTION); + obj->known = 1; + update_inventory(); } break; } @@ -756,12 +743,13 @@ boolean gone; { register long mask = obj->owornmask & W_RING; - int old_attrib; + int old_attrib, which; if(!(u.uprops[objects[obj->otyp].oc_oprop].extrinsic & mask)) impossible("Strange... I didn't know you had that ring."); if(gone) setnotworn(obj); else setworn((struct obj *)0, obj->owornmask); + switch(obj->otyp) { case RIN_TELEPORTATION: case RIN_REGENERATION: @@ -796,40 +784,40 @@ } if (Invisible && !Blind) { - newsym(u.ux,u.uy); - pline("Suddenly you cannot see yourself."); - makeknown(RIN_SEE_INVISIBLE); + newsym(u.ux,u.uy); + pline("Suddenly you cannot see yourself."); + makeknown(RIN_SEE_INVISIBLE); } break; case RIN_INVISIBILITY: if (!Invis && !BInvis && !Blind) { - newsym(u.ux,u.uy); - Your("body seems to unfade%s.", - See_invisible ? " completely" : ".."); - makeknown(RIN_INVISIBILITY); + newsym(u.ux,u.uy); + Your("body seems to unfade%s.", + See_invisible ? " completely" : ".."); + makeknown(RIN_INVISIBILITY); } break; - case RIN_ADORNMENT: - old_attrib = ACURR(A_CHA); - ABON(A_CHA) -= obj->spe; - if (ACURR(A_CHA) != old_attrib) makeknown(RIN_ADORNMENT); - flags.botl = 1; - break; case RIN_LEVITATION: (void) float_down(0L, 0L); if (!Levitation) makeknown(RIN_LEVITATION); break; case RIN_GAIN_STRENGTH: - old_attrib = ACURR(A_STR); - ABON(A_STR) -= obj->spe; - if (ACURR(A_STR) != old_attrib) makeknown(RIN_GAIN_STRENGTH); - flags.botl = 1; - break; + which = A_STR; + goto adjust_attrib; case RIN_GAIN_CONSTITUTION: - old_attrib = ACURR(A_CON); - ABON(A_CON) -= obj->spe; - flags.botl = 1; - if (ACURR(A_CON) != old_attrib) makeknown(RIN_GAIN_CONSTITUTION); + which = A_CON; + goto adjust_attrib; + case RIN_ADORNMENT: + which = A_CHA; + adjust_attrib: + old_attrib = ACURR(which); + ABON(which) -= obj->spe; + if (ACURR(which) != old_attrib) { + flags.botl = 1; + makeknown(obj->otyp); + obj->known = 1; + update_inventory(); + } break; case RIN_INCREASE_ACCURACY: /* KMH */ u.uhitinc -= obj->spe; @@ -837,6 +825,14 @@ case RIN_INCREASE_DAMAGE: u.udaminc -= obj->spe; break; + case RIN_PROTECTION: + /* might have forgotten it due to amnesia */ + if (obj->spe) { + flags.botl = 1; + makeknown(RIN_PROTECTION); + obj->known = 1; + update_inventory(); + } case RIN_PROTECTION_FROM_SHAPE_CHAN: /* If you're no longer protected, let the chameleons * change shape again -dgk @@ -966,6 +962,7 @@ static NEARDATA const char clothes[] = {ARMOR_CLASS, 0}; static NEARDATA const char accessories[] = {RING_CLASS, AMULET_CLASS, TOOL_CLASS, FOOD_CLASS, 0}; +/* the 'T' command */ int dotakeoff() { @@ -996,7 +993,8 @@ uskin->otyp >= GRAY_DRAGON_SCALES ? "dragon scales are" : "dragon scale mail is"); else - pline("Not wearing any armor."); + pline("Not wearing any armor.%s", iflags.cmdassist ? + " Use 'R' command to remove accessories." : ""); return 0; } if (armorpieces > 1) @@ -1016,41 +1014,17 @@ You_cant("take that off."); return 0; } - if (otmp == uarmg && welded(uwep)) { - You("seem unable to take off the gloves while holding your %s.", - is_sword(uwep) ? c_sword : c_weapon); - uwep->bknown = TRUE; - return 0; - } else if (welded(uwep) && bimanual(uwep) && - (otmp == uarm -#ifdef TOURIST - || otmp == uarmu -#endif - )) { - You("seem unable to take off %s while holding your %s.", - the(xname(otmp)), is_sword(uwep) ? c_sword : c_weapon); - uwep->bknown = TRUE; - return 0; - } - if (otmp == uarmg && Glib) { - You_cant("remove the slippery gloves with your slippery fingers."); - return 0; - } - if (otmp == uarmf && u.utrap && (u.utraptype == TT_BEARTRAP || - u.utraptype == TT_INFLOOR)) { /* -3. */ - if(u.utraptype == TT_BEARTRAP) - pline_The("bear trap prevents you from pulling your %s out.", - body_part(FOOT)); - else - You("are stuck in the %s, and cannot pull your %s out.", - surface(u.ux, u.uy), makeplural(body_part(FOOT))); - return(0); - } - reset_remarm(); /* since you may change ordering */ + + reset_remarm(); /* clear takeoff_mask and taking_off */ + (void) select_off(otmp); + if (!takeoff_mask) return 0; + reset_remarm(); /* armoroff() doesn't use takeoff_mask */ + (void) armoroff(otmp); return(1); } +/* the 'R' command */ int doremring() { @@ -1064,7 +1038,8 @@ MOREACC(ublindf); if(!Accessories) { - pline("Not wearing any accessories."); + pline("Not wearing any accessories.%s", iflags.cmdassist ? + " Use 'T' command to take off non-accessories." : ""); return(0); } if (Accessories != 1) otmp = getobj(accessories, "remove"); @@ -1073,32 +1048,13 @@ You("are not wearing that."); return(0); } - if(cursed(otmp)) return(0); - if(otmp->oclass == RING_CLASS || otmp->otyp == MEAT_RING) { - if (nolimbs(youmonst.data)) { - pline("It seems to be stuck."); - return(0); - } - if (uarmg && uarmg->cursed) { - uarmg->bknown = TRUE; - You( - "seem unable to remove your ring without taking off your gloves."); - return(0); - } - if (welded(uwep) && bimanual(uwep)) { - uwep->bknown = TRUE; - You( - "seem unable to remove the ring while your hands hold your %s.", - is_sword(uwep) ? c_sword : c_weapon); - return(0); - } - if (welded(uwep) && otmp==uright) { - uwep->bknown = TRUE; - You( - "seem unable to remove the ring while your right hand holds your %s.", - is_sword(uwep) ? c_sword : c_weapon); - return(0); - } + + reset_remarm(); /* clear takeoff_mask and taking_off */ + (void) select_off(otmp); + if (!takeoff_mask) return 0; + reset_remarm(); /* not used by Ring_/Amulet_/Blindf_off() */ + + if (otmp == uright || otmp == uleft) { /* Sometimes we want to give the off_msg before removing and * sometimes after; for instance, "you were wearing a moonstone * ring (on right hand)" is desired but "you were wearing a @@ -1107,10 +1063,14 @@ */ off_msg(otmp); Ring_off(otmp); - } else if(otmp->oclass == AMULET_CLASS) { + } else if (otmp == uamul) { Amulet_off(); off_msg(otmp); - } else Blindf_off(otmp); /* does its own off_msg */ + } else if (otmp == ublindf) { + Blindf_off(otmp); /* does its own off_msg */ + } else { + impossible("removing strange accessory?"); + } return(1); } @@ -1121,9 +1081,9 @@ { /* Curses, like chickens, come home to roost. */ if((otmp == uwep) ? welded(otmp) : (int)otmp->cursed) { - You("can't. %s to be cursed.", + You("can't. %s cursed.", (is_boots(otmp) || is_gloves(otmp) || otmp->quan > 1L) - ? "They seem" : "It seems"); + ? "They are" : "It is"); otmp->bknown = TRUE; return(1); } @@ -1219,7 +1179,8 @@ is_suit(otmp) ? c_suit : 0; if (which && cantweararm(youmonst.data) && /* same exception for cloaks as used in m_dowear() */ - (which != c_cloak || youmonst.data->msize != MZ_SMALL)) { + (which != c_cloak || youmonst.data->msize != MZ_SMALL) && + (racial_exception(&youmonst, otmp) < 1)) { if (noisy) pline_The("%s will not fit on your body.", which); return 0; } else if (otmp->owornmask & W_ARMOR) { @@ -1228,11 +1189,11 @@ } if (welded(uwep) && bimanual(uwep) && - (otmp == uarm + (is_suit(otmp) #ifdef TOURIST - || otmp == uarmu + || is_shirt(otmp) #endif - )) { + )) { if (noisy) You("cannot do that while holding your %s.", is_sword(uwep) ? c_sword : c_weapon); @@ -1243,6 +1204,12 @@ if (uarmh) { if (noisy) already_wearing(an(c_helmet)); err++; + } else if (Upolyd && has_horns(youmonst.data) && !is_flimsy(otmp)) { + /* (flimsy exception matches polyself handling) */ + if (noisy) + pline_The("%s won't fit over your horn%s.", + c_helmet, plur(num_horns(youmonst.data))); + err++; } else *mask = W_ARMH; } else if (is_shield(otmp)) { @@ -1268,6 +1235,13 @@ } else if (Upolyd && slithy(youmonst.data)) { if (noisy) You("have no feet..."); /* not body_part(FOOT) */ err++; + } else if (Upolyd && youmonst.data->mlet == S_CENTAUR) { + /* break_armor() pushes boots off for centaurs, + so don't let dowear() put them back on... */ + if (noisy) pline("You have too many hooves to wear %s.", + c_boots); /* makeplural(body_part(FOOT)) yields + "rear hooves" which sounds odd */ + err++; } else if (u.utrap && (u.utraptype == TT_BEARTRAP || u.utraptype == TT_INFLOOR)) { if (u.utraptype == TT_BEARTRAP) { @@ -1322,7 +1296,7 @@ /* getobj can't do this after setting its allow_all flag; that happens if you have armor for slots that are covered up or extra armor for slots that are filled */ - if (noisy) pline(silly_thing_to, "wear"); + if (noisy) silly_thing("wear", otmp); err++; } /* Unnecessary since now only weapons and special items like pick-axes get @@ -1361,7 +1335,10 @@ if (otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT && qstart_level.dnum == u.uz.dnum) { /* in quest */ - You("narrowly avoid losing all chance at your goal."); + if (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL]) + You("narrowly avoid losing all chance at your goal."); + else /* converted */ + You("are suddenly overcome with shame and change your mind."); u.ublessed = 0; /* lose your god's protection */ makeknown(otmp->otyp); flags.botl = 1; @@ -1553,6 +1530,7 @@ register struct obj *otmp; int xfl = 0; boolean leftfall, rightfall; + const char *otherwep = 0; leftfall = (uleft && !uleft->cursed && (!uwep || !welded(uwep) || !bimanual(uwep))); @@ -1561,7 +1539,8 @@ /* changed so cursed rings don't fall off, GAN 10/30/86 */ Your("%s off your %s.", (leftfall && rightfall) ? "rings slip" : "ring slips", - makeplural(body_part(FINGER))); + (leftfall && rightfall) ? makeplural(body_part(FINGER)) : + body_part(FINGER)); xfl++; if (leftfall) { otmp = uleft; @@ -1577,9 +1556,10 @@ otmp = uswapwep; if (u.twoweap && otmp) { + otherwep = is_sword(otmp) ? c_sword : + makesingular(oclass_names[(int)otmp->oclass]); Your("%s %sslips from your %s.", - is_sword(otmp) ? c_sword : - makesingular(oclass_names[(int)otmp->oclass]), + otherwep, xfl ? "also " : "", makeplural(body_part(HAND))); setuswapwep((struct obj *)0); @@ -1589,10 +1569,16 @@ } otmp = uwep; if (otmp && !welded(otmp)) { + const char *thiswep; + + /* nice wording if both weapons are the same type */ + thiswep = is_sword(otmp) ? c_sword : + makesingular(oclass_names[(int)otmp->oclass]); + if (otherwep && strcmp(thiswep, otherwep)) otherwep = 0; + /* changed so cursed weapons don't fall, GAN 10/30/86 */ - Your("%s %sslips from your %s.", - is_sword(otmp) ? c_sword : - makesingular(oclass_names[(int)otmp->oclass]), + Your("%s%s %sslips from your %s.", + otherwep ? "other " : "", thiswep, xfl ? "also " : "", makeplural(body_part(HAND))); setuwep((struct obj *)0); @@ -1640,50 +1626,121 @@ } } +/* used for praying to check and fix levitation trouble */ +struct obj * +stuck_ring(ring, otyp) +struct obj *ring; +int otyp; +{ + if (ring != uleft && ring != uright) { + impossible("stuck_ring: neither left nor right?"); + return (struct obj *)0; + } + + if (ring && ring->otyp == otyp) { + /* reasons ring can't be removed match those checked by select_off(); + limbless case has extra checks because ordinarily it's temporary */ + if (nolimbs(youmonst.data) && + uamul && uamul->otyp == AMULET_OF_UNCHANGING && uamul->cursed) + return uamul; + if (welded(uwep) && (ring == uright || bimanual(uwep))) return uwep; + if (uarmg && uarmg->cursed) return uarmg; + if (ring->cursed) return ring; + } + /* either no ring or not right type or nothing prevents its removal */ + return (struct obj *)0; +} + STATIC_PTR int select_off(otmp) register struct obj *otmp; { + struct obj *why; char buf[BUFSZ]; - if(!otmp) return(0); - if(cursed(otmp)) return(0); - if((otmp->oclass==RING_CLASS || otmp->otyp == MEAT_RING) - && nolimbs(youmonst.data)) - return(0); - if(welded(uwep) && (otmp==uarmg || otmp==uright || (otmp==uleft - && bimanual(uwep)))) { - You("cannot free a weapon hand to take off the ring."); - return(0); + if (!otmp) return 0; + *buf = '\0'; /* lint suppresion */ + + /* special ring checks */ + if (otmp == uright || otmp == uleft) { + if (nolimbs(youmonst.data)) { + pline_The("ring is stuck."); + return 0; + } + why = 0; /* the item which prevents ring removal */ + if (welded(uwep) && (otmp == uright || bimanual(uwep))) { + Sprintf(buf, "free a weapon %s", body_part(HAND)); + why = uwep; + } else if (uarmg && uarmg->cursed) { + Sprintf(buf, "take off your %s", c_gloves); + why = uarmg; + } + if (why) { + You("cannot %s to remove the ring.", buf); + why->bknown = TRUE; + return 0; + } } - if(uarmg && uarmg->cursed && (otmp==uright || otmp==uleft)) { - uarmg->bknown = TRUE; - You("cannot remove your gloves to take off the ring."); - return(0); + /* special glove checks */ + if (otmp == uarmg) { + if (welded(uwep)) { + You("are unable to take off your %s while wielding that %s.", + c_gloves, is_sword(uwep) ? c_sword : c_weapon); + uwep->bknown = TRUE; + return 0; + } else if (Glib) { + You_cant("take off the slippery %s with your slippery %s.", + c_gloves, makeplural(body_part(FINGER))); + return 0; + } } - if(otmp == uarmf && u.utrap && (u.utraptype == TT_BEARTRAP || - u.utraptype == TT_INFLOOR)) { - return (0); + /* special boot checks */ + if (otmp == uarmf) { + if (u.utrap && u.utraptype == TT_BEARTRAP) { + pline_The("bear trap prevents you from pulling your %s out.", + body_part(FOOT)); + return 0; + } else if (u.utrap && u.utraptype == TT_INFLOOR) { + You("are stuck in the %s, and cannot pull your %s out.", + surface(u.ux, u.uy), makeplural(body_part(FOOT))); + return 0; + } } - if((otmp==uarm + /* special suit and shirt checks */ + if (otmp == uarm #ifdef TOURIST - || otmp==uarmu + || otmp == uarmu #endif - ) && uarmc && uarmc->cursed) { - Strcpy(buf, the(xname(uarmc))); - You("cannot remove %s to take off %s.", buf, the(xname(otmp))); - uarmc->bknown = TRUE; - return(0); - } + ) { + why = 0; /* the item which prevents disrobing */ + if (uarmc && uarmc->cursed) { + Sprintf(buf, "remove your %s", cloak_simple_name(uarmc)); + why = uarmc; #ifdef TOURIST - if(otmp==uarmu && uarm && uarm->cursed) { - Strcpy(buf, the(xname(uarm))); - You("cannot remove %s to take off %s.", buf, the(xname(otmp))); - uarm->bknown = TRUE; - return(0); - } + } else if (otmp == uarmu && uarm && uarm->cursed) { + Sprintf(buf, "remove your %s", c_suit); + why = uarm; #endif + } else if (welded(uwep) && bimanual(uwep)) { + Sprintf(buf, "release your %s", + is_sword(uwep) ? c_sword : + (uwep->otyp == BATTLE_AXE) ? c_axe : c_weapon); + why = uwep; + } + if (why) { + You("cannot %s to take off %s.", buf, the(xname(otmp))); + why->bknown = TRUE; + return 0; + } + } + /* basic curse check */ + if (otmp == uquiver || (otmp == uswapwep && !u.twoweap)) { + ; /* some items can be removed even when cursed */ + } else { + /* otherwise, this is fundamental */ + if (cursed(otmp)) return 0; + } if(otmp == uarm) takeoff_mask |= WORN_ARMOR; else if(otmp == uarmc) takeoff_mask |= WORN_CLOAK; @@ -1765,6 +1822,8 @@ return(otmp); } +static const char *disrobing = ""; + STATIC_PTR int take_off() @@ -1772,13 +1831,13 @@ register int i; register struct obj *otmp; - if(taking_off) { - if(todelay > 0) { - + if (taking_off) { + if (todelay > 0) { todelay--; return(1); /* still busy */ - } else if((otmp = do_takeoff())) off_msg(otmp); - + } else { + if ((otmp = do_takeoff())) off_msg(otmp); + } takeoff_mask &= ~taking_off; taking_off = 0L; } @@ -1793,7 +1852,7 @@ todelay = 0; if (taking_off == 0L) { - You("finish disrobing."); + You("finish %s.", disrobing); return 0; } else if (taking_off == W_WEP) { todelay = 1; @@ -1846,30 +1905,26 @@ */ if (todelay>0) todelay--; - set_occupation(take_off, "disrobing", 0); + set_occupation(take_off, disrobing, 0); return(1); /* get busy */ } -#endif /* OVLB */ -#ifdef OVL1 - void reset_remarm() { taking_off = takeoff_mask = 0L; + disrobing = nul; } -#endif /* OVL1 */ -#ifdef OVLB - +/* the 'A' command */ int doddoremarm() { int result = 0; if (taking_off || takeoff_mask) { - You("continue disrobing."); - set_occupation(take_off, "disrobing", 0); + You("continue %s.", disrobing); + set_occupation(take_off, disrobing, 0); (void) take_off(); return 0; } else if (!uwep && !uswapwep && !uquiver && !uamul && !ublindf && @@ -1883,8 +1938,15 @@ (result = ggetobj("take off", select_off, 0, FALSE, (unsigned *)0)) < -1) result = menu_remarm(result); - if (takeoff_mask) + if (takeoff_mask) { + /* default activity for armor and/or accessories, + possibly combined with weapons */ + disrobing = "disrobing"; + /* specific activity when handling weapons only */ + if (!(takeoff_mask & ~(W_WEP|W_SWAPWEP|W_QUIVER))) + disrobing = "disarming"; (void) take_off(); + } /* The time to perform the command is already completely accounted for * in take_off(); if we return 1, that would add an extra turn to each * disrobe. diff -Naurd ../nethack-3.4.0/src/dog.c ./src/dog.c --- ../nethack-3.4.0/src/dog.c Wed Mar 20 23:43:03 2002 +++ ./src/dog.c Mon Feb 24 15:25:05 2003 @@ -56,8 +56,20 @@ int chance, trycnt = 100; do { - if (otmp) { - pm = &mons[otmp->corpsenm]; /* Figurine; otherwise spell */ + if (otmp) { /* figurine; otherwise spell */ + int mndx = otmp->corpsenm; + pm = &mons[mndx]; + /* activating a figurine provides one way to exceed the + maximum number of the target critter created--unless + it has a special limit (erinys, Nazgul) */ + if ((mvitals[mndx].mvflags & G_EXTINCT) && + mbirth_limit(mndx) != MAXMONNO) { + if (!quietly) + /* have just been given "You + the figurine and it transforms." message */ + pline("... into a pile of dust."); + break; /* mtmp is null */ + } } else if (!rn2(3)) { pm = &mons[pet_type()]; } else { @@ -69,7 +81,7 @@ } } - mtmp = makemon(pm, x, y, MM_EDOG); + mtmp = makemon(pm, x, y, MM_EDOG|MM_IGNOREWATER); if (otmp && !mtmp) { /* monster was genocided or square occupied */ if (!quietly) pline_The("figurine writhes and then shatters into pieces!"); @@ -79,6 +91,9 @@ if (!mtmp) return (struct monst *)0; + if (is_pool(mtmp->mx, mtmp->my) && minliquid(mtmp)) + return (struct monst *)0; + initedog(mtmp); mtmp->msleeping = 0; if (otmp) { /* figurine; resulting monster might not become a pet */ @@ -152,7 +167,7 @@ otmp->dknown = otmp->bknown = otmp->rknown = 1; otmp->owornmask = W_SADDLE; otmp->leashmon = mtmp->m_id; - update_mon_intrinsics(mtmp, otmp, TRUE); + update_mon_intrinsics(mtmp, otmp, TRUE, TRUE); } #endif @@ -453,7 +468,13 @@ the amulet; if you don't have it, will chase you only if in range. -3. */ (u.uhave.amulet && mtmp->iswiz)) - && !mtmp->msleeping && mtmp->mcanmove + && ((!mtmp->msleeping && mtmp->mcanmove) +#ifdef STEED + /* eg if level teleport or new trap, steed has no control + to avoid following */ + || (mtmp == u.usteed) +#endif + ) /* monster won't follow if it hasn't noticed you yet */ && !(mtmp->mstrategy & STRAT_WAITFORU)) { stay_behind = FALSE; @@ -596,6 +617,7 @@ boolean carni = carnivorous(mon->data); boolean herbi = herbivorous(mon->data); struct permonst *fptr = &mons[obj->corpsenm]; + boolean starving; if (is_quest_artifact(obj) || obj_resists(obj, 0, 95)) return (obj->cursed ? TABU : APPORT); @@ -609,12 +631,17 @@ /* Ghouls only eat old corpses... yum! */ if (mon->data == &mons[PM_GHOUL]) - return (obj->otyp == CORPSE && obj->age+50 <= monstermoves) ? - DOGFOOD : TABU; + return (obj->otyp == CORPSE && + peek_at_iced_corpse_age(obj) + 50L <= monstermoves) ? + DOGFOOD : TABU; if (!carni && !herbi) return (obj->cursed ? UNDEF : APPORT); + /* a starving pet will eat almost anything */ + starving = (mon->mtame && !mon->isminion && + EDOG(mon)->mhpmax_penalty); + switch (obj->otyp) { case TRIPE_RATION: case MEATBALL: @@ -627,7 +654,7 @@ return POISON; return (carni ? CADAVER : MANFOOD); case CORPSE: - if ((peek_at_iced_corpse_age(obj)+50 <= monstermoves + if ((peek_at_iced_corpse_age(obj) + 50L <= monstermoves && obj->corpsenm != PM_LIZARD && obj->corpsenm != PM_LICHEN && mon->data->mlet != S_FUNGUS) || @@ -640,24 +667,25 @@ else return (carni ? CADAVER : MANFOOD); case CLOVE_OF_GARLIC: return (is_undead(mon->data) ? TABU : - (herbi ? ACCFOOD : MANFOOD)); + ((herbi || starving) ? ACCFOOD : MANFOOD)); case TIN: return (metallivorous(mon->data) ? ACCFOOD : MANFOOD); case APPLE: case CARROT: - return (herbi ? DOGFOOD : MANFOOD); + return (herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD); case BANANA: return ((mon->data->mlet == S_YETI) ? DOGFOOD : - (herbi ? ACCFOOD : MANFOOD)); + ((herbi || starving) ? ACCFOOD : MANFOOD)); default: + if (starving) return ACCFOOD; return (obj->otyp > SLIME_MOLD ? (carni ? ACCFOOD : MANFOOD) : (herbi ? ACCFOOD : MANFOOD)); } default: if (obj->otyp == AMULET_OF_STRANGULATION || - obj->otyp == RIN_SLOW_DIGESTION) - return (TABU); + obj->otyp == RIN_SLOW_DIGESTION) + return TABU; if (hates_silver(mon->data) && objects[obj->otyp].oc_material == SILVER) return(TABU); @@ -783,19 +811,28 @@ * If the pet wasn't abused and was very tame, it might revive tame. */ void -wary_dog(mtmp, quietly) +wary_dog(mtmp, was_dead) struct monst *mtmp; -boolean quietly; +boolean was_dead; { - int has_edog; + struct edog *edog; + boolean quietly = was_dead; + mtmp->meating = 0; if (!mtmp->mtame) return; - has_edog = !mtmp->isminion; - if (has_edog && - ((EDOG(mtmp)->killed_by_u == 1) || (EDOG(mtmp)->abuse > 2))) { + edog = !mtmp->isminion ? EDOG(mtmp) : 0; + + /* if monster was starving when it died, undo that now */ + if (edog && edog->mhpmax_penalty) { + mtmp->mhpmax += edog->mhpmax_penalty; + mtmp->mhp += edog->mhpmax_penalty; /* heal it */ + edog->mhpmax_penalty = 0; + } + + if (edog && (edog->killed_by_u == 1 || edog->abuse > 2)) { mtmp->mpeaceful = mtmp->mtame = 0; - if (EDOG(mtmp)->abuse >= 0 && EDOG(mtmp)->abuse < 10) - if (!rn2(EDOG(mtmp)->abuse + 1)) mtmp->mpeaceful = 1; + if (edog->abuse >= 0 && edog->abuse < 10) + if (!rn2(edog->abuse + 1)) mtmp->mpeaceful = 1; if(!quietly && cansee(mtmp->mx, mtmp->my)) { if (haseyes(youmonst.data)) { if (haseyes(mtmp->data)) @@ -810,10 +847,10 @@ } } } else { - /* chance it goes wild anyway - Pet Semetary */ - if (!rn2(mtmp->mtame)) { - mtmp->mpeaceful = mtmp->mtame = 0; - } + /* chance it goes wild anyway - Pet Semetary */ + if (!rn2(mtmp->mtame)) { + mtmp->mpeaceful = mtmp->mtame = 0; + } } if (!mtmp->mtame) { newsym(mtmp->mx, mtmp->my); @@ -823,10 +860,19 @@ } /* if its still a pet, start a clean pet-slate now */ - if (has_edog && mtmp->mtame) { - EDOG(mtmp)->revivals++; - EDOG(mtmp)->killed_by_u = 0; - EDOG(mtmp)->abuse = 0; + if (edog && mtmp->mtame) { + edog->revivals++; + edog->killed_by_u = 0; + edog->abuse = 0; + edog->ogoal.x = edog->ogoal.y = -1; + if (was_dead || edog->hungrytime < monstermoves + 500L) + edog->hungrytime = monstermoves + 500L; + if (was_dead) { + edog->droptime = 0L; + edog->dropdist = 10000; + edog->whistletime = 0L; + edog->apport = 5; + } /* else lifesaved, so retain current values */ } } diff -Naurd ../nethack-3.4.0/src/dogmove.c ./src/dogmove.c --- ../nethack-3.4.0/src/dogmove.c Wed Mar 20 23:43:03 2002 +++ ./src/dogmove.c Mon Feb 24 15:25:05 2003 @@ -100,7 +100,7 @@ mtmp->meating = eaten_stat(mtmp->meating, obj); nutrit = eaten_stat(nutrit, obj); } - } else if (obj->oclass == GOLD_CLASS) { + } else if (obj->oclass == COIN_CLASS) { mtmp->meating = (int)(obj->quan/2000) + 1; if (mtmp->meating < 0) mtmp->meating = 1; nutrit = (int)(obj->quan/20); @@ -191,23 +191,8 @@ delobj(obj); if (poly) { - char oldpet[BUFSZ]; -#ifdef STEED - long mw = mtmp->misc_worn_check; - - mtmp->misc_worn_check &= ~W_SADDLE; -#endif - Strcpy(oldpet, Monnam(mtmp)); -#ifdef STEED - mtmp->misc_worn_check = mw; -#endif - if (newcham(mtmp, (struct permonst *)0, FALSE) && - cansee(mtmp->mx, mtmp->my)) { - uchar save_mnamelth = mtmp->mnamelth; - mtmp->mnamelth = 0; - pline("%s turns into %s!", oldpet, a_monnam(mtmp)); - mtmp->mnamelth = save_mnamelth; - } + (void) newcham(mtmp, (struct permonst *)0, FALSE, + cansee(mtmp->mx, mtmp->my)); } /* limit "instant" growth to prevent potential abuse */ if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) { @@ -247,12 +232,15 @@ You_feel("worried about %s.", y_monnam(mtmp)); stop_occupation(); } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) { - dog_died: - if (mtmp->mleashed) + dog_died: + if (mtmp->mleashed +#ifdef STEED + && mtmp != u.usteed +#endif + ) Your("leash goes slack."); else if (cansee(mtmp->mx, mtmp->my)) - pline("%s dies%s.", Monnam(mtmp), - (mtmp->mhp >= 1) ? "" : " from hunger"); + pline("%s starves.", Monnam(mtmp)); else You_feel("%s for a moment.", Hallucination ? "bummed" : "sad"); @@ -301,7 +289,11 @@ && obj->otyp != SCR_MAIL #endif ){ - if (dogfood(mtmp, obj) <= CADAVER) + int edible = dogfood(mtmp, obj); + + if (edible <= CADAVER || + /* starving pet is more aggressive about eating */ + (edog->mhpmax_penalty && edible == ACCFOOD)) return dog_eat(mtmp, obj, omx, omy, FALSE); if(can_carry(mtmp, obj) && !obj->cursed && @@ -338,12 +330,11 @@ int after, udist, whappr; { register int omx, omy; - boolean in_masters_sight; + boolean in_masters_sight, dog_has_minvent; register struct obj *obj; xchar otyp; int appr; - #ifdef STEED /* Steeds don't move on their own will */ if (mtmp == u.usteed) @@ -354,6 +345,7 @@ omy = mtmp->my; in_masters_sight = couldsee(omx, omy); + dog_has_minvent = (DROPPABLES(mtmp) != 0); if (!edog || mtmp->mleashed) { /* he's not going anywhere... */ gtyp = APPORT; @@ -368,7 +360,7 @@ gtyp = UNDEF; /* no goal as yet */ gx = gy = 0; /* suppress 'used before set' message */ - if ((min_x = omx - SQSRCHRADIUS) < 0) min_x = 0; + if ((min_x = omx - SQSRCHRADIUS) < 1) min_x = 1; if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1; if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0; if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1; @@ -379,9 +371,12 @@ ny = obj->oy; if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) { otyp = dogfood(mtmp, obj); + /* skip inferior goals */ if (otyp > gtyp || otyp == UNDEF) continue; - if (cursed_object_at(nx, ny)) + /* avoid cursed items unless starving */ + if (cursed_object_at(nx, ny) && + !(edog->mhpmax_penalty && otyp < MANFOOD)) continue; if (otyp < MANFOOD && can_reach_food(mtmp, mtmp->mx, mtmp->my, nx, ny)) { @@ -391,7 +386,7 @@ gtyp = otyp; } } else if(gtyp == UNDEF && in_masters_sight && - !mtmp->minvent && + !dog_has_minvent && (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) && (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) && edog->apport > rn2(8) && @@ -415,7 +410,7 @@ if (udist > 1) { if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || whappr || - (mtmp->minvent && rn2(edog->apport))) + (dog_has_minvent && rn2(edog->apport))) appr = 1; } /* if you have dog food it'll follow you more closely */ @@ -539,7 +534,8 @@ if (appr == -2) return(0); allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT; - if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL); + if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL); + if (passes_bars(mtmp->data)) allowflags |= ALLOW_BARS; if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { allowflags |= ALLOW_U; @@ -575,10 +571,7 @@ if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; } if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; - if (tunnels(mtmp->data) && (!needspick(mtmp->data) || - m_carrying(mtmp, PICK_AXE) || - m_carrying(mtmp, DWARVISH_MATTOCK))) - allowflags |= ALLOW_DIG; + if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG; cnt = mfndpos(mtmp, poss, info, allowflags); /* Normally dogs don't step on cursed items, but if they have no @@ -724,12 +717,22 @@ } if (!m_in_out_region(mtmp, nix, niy)) return 1; - if(IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy) && + if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) || + closed_door(nix, niy)) && mtmp->weapon_check != NO_WEAPON_WANTED && - tunnels(mtmp->data) && needspick(mtmp->data) && - (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp))) { - mtmp->weapon_check = NEED_PICK_AXE; - if (mon_wield_item(mtmp)) + tunnels(mtmp->data) && needspick(mtmp->data)) { + if (closed_door(nix, niy)) { + if (!(mw_tmp = MON_WEP(mtmp)) || + !is_pick(mw_tmp) || !is_axe(mw_tmp)) + mtmp->weapon_check = NEED_PICK_OR_AXE; + } else if (IS_TREE(levl[nix][niy].typ)) { + if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) + mtmp->weapon_check = NEED_AXE; + } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { + mtmp->weapon_check = NEED_PICK_AXE; + } + if (mtmp->weapon_check >= NEED_PICK_AXE && + mon_wield_item(mtmp)) return 0; } /* insert a worm_move() if worms ever begin to eat things */ @@ -757,16 +760,16 @@ ny = sgn(omy - u.uy); cc.x = u.ux + nx; cc.y = u.uy + ny; - if (goodpos(cc.x, cc.y, mtmp)) goto dognext; + if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; i = xytod(nx, ny); for (j = (i + 7)%8; j < (i + 1)%8; j++) { dtoxy(&cc, j); - if (goodpos(cc.x, cc.y, mtmp)) goto dognext; + if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; } for (j = (i + 6)%8; j < (i + 2)%8; j++) { dtoxy(&cc, j); - if (goodpos(cc.x, cc.y, mtmp)) goto dognext; + if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; } cc.x = mtmp->mx; cc.y = mtmp->my; diff -Naurd ../nethack-3.4.0/src/dokick.c ./src/dokick.c --- ../nethack-3.4.0/src/dokick.c Wed Mar 20 23:43:03 2002 +++ ./src/dokick.c Mon Feb 24 15:25:05 2003 @@ -34,6 +34,7 @@ register int dmg = ( ACURRSTR + ACURR(A_DEX) + ACURR(A_CON) )/ 15; int kick_skill = P_NONE; int blessed_foot_damage = 0; + boolean trapkilled = FALSE; if (uarmf && uarmf->otyp == KICKING_BOOTS) dmg += 5; @@ -61,14 +62,7 @@ if(mon->m_ap_type) seemimic(mon); - /* it is unchivalrous to attack the defenseless or from behind */ - if (Role_if(PM_KNIGHT) && - u.ualign.type == A_LAWFUL && u.ualign.record > -10 && - (!mon->mcanmove || mon->msleeping || - (mon->mflee && !mon->mavenge))) { - You_feel("like a caitiff!"); - adjalign(-1); - } + check_caitiff(mon); /* squeeze some guilt feelings... */ if(mon->mtame) { @@ -99,7 +93,7 @@ /* see if the monster has a place to move into */ mdx = mon->mx + u.dx; mdy = mon->my + u.dy; - if(goodpos(mdx, mdy, mon)) { + if(goodpos(mdx, mdy, mon, 0)) { pline("%s reels from the blow.", Monnam(mon)); if (m_in_out_region(mon, mdx, mdy)) { remove_monster(mon->mx, mon->my); @@ -107,13 +101,13 @@ place_monster(mon, mdx, mdy); newsym(mon->mx, mon->my); set_apparxy(mon); - (void) mintrap(mon); + if (mintrap(mon) == 2) trapkilled = TRUE; } } } (void) passive(mon, TRUE, mon->mhp > 0, AT_KICK); - if (mon->mhp <= 0) killed(mon); + if (mon->mhp <= 0 && !trapkilled) killed(mon); /* may bring up a dialog, so put this after all messages */ if (kick_skill != P_NONE) /* exercise proficiency */ @@ -214,6 +208,10 @@ } else { mnexto(mon); if(mon->mx != x || mon->my != y) { + if(glyph_is_invisible(levl[x][y].glyph)) { + unmap_object(x, y); + newsym(x, y); + } pline("%s %s, %s evading your %skick.", Monnam(mon), (can_teleport(mon->data) ? "teleports" : is_floater(mon->data) ? "floats" : @@ -408,6 +406,37 @@ costly_spot(x, y)); insider = (*u.ushops && inside_shop(u.ux, u.uy) && *in_rooms(x, y, SHOPBASE) == *u.ushops); + isgold = (kickobj->oclass == COIN_CLASS); + + if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) { + if ((!martial() && rn2(20) > ACURR(A_DEX)) || + IS_ROCK(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy)) { + if (Blind) + pline("It doesn't come loose."); + else + pline("%s %sn't come loose.", + The(distant_name(kickobj, xname)), + otense(kickobj, "do")); + return (!rn2(3) || martial()); + } + if (Blind) + pline("It comes loose."); + else + pline("%s %s loose.", + The(distant_name(kickobj, xname)), + otense(kickobj, "come")); + obj_extract_self(kickobj); + newsym(x, y); + if (costly && (!costly_spot(u.ux, u.uy) || + !index(u.urooms, *in_rooms(x, y, SHOPBASE)))) + addtobill(kickobj, FALSE, FALSE, FALSE); + if (!flooreffects(kickobj, u.ux, u.uy, "fall")) { + place_object(kickobj, u.ux, u.uy); + stackobj(kickobj); + newsym(u.ux, u.uy); + } + return 1; + } /* a box gets a chance of breaking open here */ if(Is_box(kickobj)) { @@ -480,35 +509,6 @@ /* fragile objects should not be kicked */ if (hero_breaks(kickobj, kickobj->ox, kickobj->oy, FALSE)) return 1; - if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) { - if ((!martial() && rn2(20) > ACURR(A_DEX)) - || IS_ROCK(levl[u.ux][u.uy].typ) - || closed_door(u.ux, u.uy)) { - if (Blind) pline("It doesn't come loose."); - else pline("%s %sn't come loose.", - The(distant_name(kickobj, xname)), - otense(kickobj, "do")); - return(!rn2(3) || martial()); - } - if (Blind) pline("It comes loose."); - else pline("%s %s loose.", - The(distant_name(kickobj, xname)), - otense(kickobj, "come")); - obj_extract_self(kickobj); - newsym(x, y); - if (costly && (!costly_spot(u.ux, u.uy) - || !index(u.urooms, *in_rooms(x, y, SHOPBASE)))) - addtobill(kickobj, FALSE, FALSE, FALSE); - if(!flooreffects(kickobj,u.ux,u.uy,"fall")) { - place_object(kickobj, u.ux, u.uy); - stackobj(kickobj); - newsym(u.ux, u.uy); - } - return(1); - } - - isgold = (kickobj->oclass == GOLD_CLASS); - /* too heavy to move. range is calculated as potential distance from * player, so range == 2 means the object may move up to one square * from its current position @@ -543,8 +543,15 @@ } /* the object might have fallen down a hole */ - if (kickobj->where == OBJ_MIGRATING) + if (kickobj->where == OBJ_MIGRATING) { + if (costly) { + if(isgold) + costly_gold(x, y, kickobj->quan); + else (void)stolen_value(kickobj, x, y, + (boolean)shkp->mpeaceful, FALSE); + } return 1; + } bhitroom = *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE); if (costly && (!costly_spot(bhitpos.x, bhitpos.y) || @@ -594,7 +601,6 @@ register int x, y; int avrg_attrib; register struct monst *mtmp; - s_level *slev; boolean no_kick = FALSE; char buf[BUFSZ]; @@ -628,6 +634,9 @@ } else if (near_capacity() > SLT_ENCUMBER) { Your("load is too heavy to balance yourself for a kick."); no_kick = TRUE; + } else if (youmonst.data->mlet == S_LIZARD) { + Your("legs cannot kick effectively."); + no_kick = TRUE; } else if (u.uinwater && !rn2(2)) { Your("slow motion kick doesn't hit anything."); no_kick = TRUE; @@ -712,7 +721,8 @@ kick_monster(x, y); flags.forcefight = FALSE; /* see comment in attack_checks() */ - if (!canspotmon(mtmp) && + if (!DEADMONSTER(mtmp) && + !canspotmon(mtmp) && /* check x and y; a monster that evades your kick by jumping to an unseen square doesn't leave an I behind */ mtmp->mx == x && mtmp->my == y && @@ -811,7 +821,9 @@ (void) mkgold((long) rn1(201, 300), x, y); i = Luck + 1; if(i > 6) i = 6; - while(i--) (void) mkobj_at(GEM_CLASS, x, y, TRUE); + while(i--) + (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, + LUCKSTONE-1), x, y, FALSE, TRUE); if (Blind) You("kick %s loose!", something); else { @@ -854,30 +866,46 @@ goto ouch; if(IS_TREE(maploc->typ)) { struct obj *treefruit; - if (rn2(8)) goto ouch; - /* fruit or trouble ? */ - if (!rn2(2) && !(maploc->looted & TREE_LOOTED) && + /* nothing, fruit or trouble? 75:23.5:1.5% */ + if (rn2(3)) { + if ( !rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE) ) + You_hear("a low buzzing."); /* a warning */ + goto ouch; + } + if (rn2(15) && !(maploc->looted & TREE_LOOTED) && (treefruit = rnd_treefruit_at(x, y))) { - treefruit->quan = (long)(8 - rnl(8)); + long nfruit = 8L-rnl(7), nfall; + treefruit->quan = nfruit; if (is_plural(treefruit)) pline("Some %s fall from the tree!", xname(treefruit)); else pline("%s falls from the tree!", An(xname(treefruit))); - scatter(x,y,2,MAY_HIT,treefruit); + nfall = scatter(x,y,2,MAY_HIT,treefruit); + if ( nfall != nfruit ) { + /* scatter left some in the tree */ + pline("%ld %s got caught in the branches.", + nfruit-nfall, xname(treefruit)); + } exercise(A_DEX, TRUE); exercise(A_WIS, TRUE); /* discovered a new food source! */ newsym(x, y); maploc->looted |= TREE_LOOTED; return(1); - } else if (!rn2(15) && !(maploc->looted & TREE_SWARM)){ - int cnt = rnl(5); + } else if (!(maploc->looted & TREE_SWARM)) { + int cnt = rnl(4) + 2; + int made = 0; coord mm; mm.x = x; mm.y = y; - pline("You've attracted the tree's former occupants!"); - while (cnt--) - if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE])) - (void) makemon(&mons[PM_KILLER_BEE], - mm.x, mm.y, MM_ANGRY); + while (cnt--) { + if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE]) + && makemon(&mons[PM_KILLER_BEE], + mm.x, mm.y, MM_ANGRY)) + made++; + } + if ( made ) + pline("You've attracted the tree's former occupants!"); + else + You("smell stale honey."); maploc->looted |= TREE_SWARM; return(1); } @@ -902,7 +930,7 @@ You_hear("a gushing sound."); else pline("A %s ooze gushes up from the drain!", - hcolor(Black)); + hcolor(NH_BLACK)); (void) makemon(&mons[PM_BLACK_PUDDING], x, y, NO_MM_FLAGS); exercise(A_DEX, TRUE); @@ -1011,9 +1039,9 @@ unblock_point(x,y); /* vision */ if (shopdoor) { add_damage(x, y, 400L); - pay_for_damage("break"); + pay_for_damage("break", FALSE); } - if ((slev = Is_special(&u.uz)) && slev->flags.town) + if (in_town(x, y)) for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if((mtmp->data == &mons[PM_WATCHMAN] || @@ -1033,7 +1061,7 @@ if (Blind) feel_location(x,y); /* we know we hit it */ exercise(A_STR, TRUE); pline("WHAMMM!!!"); - if ((slev = Is_special(&u.uz)) && slev->flags.town) + if (in_town(x, y)) for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->data == &mons[PM_WATCHMAN] || @@ -1155,7 +1183,7 @@ /* set obj->no_charge to 0 */ if (Has_contents(obj)) picked_container(obj); /* does the right thing */ - if (obj->oclass != GOLD_CLASS) + if (obj->oclass != COIN_CLASS) obj->no_charge = 0; } @@ -1276,7 +1304,7 @@ /* set otmp->no_charge to 0 */ if(container) picked_container(otmp); /* happens to do the right thing */ - if(otmp->oclass != GOLD_CLASS) + if(otmp->oclass != COIN_CLASS) otmp->no_charge = 0; } @@ -1286,7 +1314,8 @@ /* some things break rather than ship */ if (breaktest(otmp)) { - char *result; + const char *result; + if (objects[otmp->otyp].oc_material == GLASS #ifdef TOURIST || otmp->otyp == EXPENSIVE_CAMERA @@ -1311,6 +1340,8 @@ otmp->ox = cc.x; otmp->oy = cc.y; otmp->owornmask = (long)toloc; + /* boulder from rolling boulder trap, no longer part of the trap */ + if (otmp->otyp == BOULDER) otmp->otrapped = 0; if(impact) { /* the objs impacted may be in a shop other than @@ -1359,7 +1390,7 @@ if (nx > 0) { place_object(otmp, nx, ny); stackobj(otmp); - scatter(nx, ny, rnd(2), 0, otmp); + (void)scatter(nx, ny, rnd(2), 0, otmp); } else { /* random location */ /* set dummy coordinates because there's no current position for rloco() to update */ diff -Naurd ../nethack-3.4.0/src/dothrow.c ./src/dothrow.c --- ../nethack-3.4.0/src/dothrow.c Wed Mar 20 23:43:03 2002 +++ ./src/dothrow.c Mon Feb 24 15:25:05 2003 @@ -21,10 +21,12 @@ static NEARDATA const char toss_objs[] = - { ALLOW_COUNT, GOLD_CLASS, ALL_CLASSES, WEAPON_CLASS, 0 }; + { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, WEAPON_CLASS, 0 }; /* different default choices when wielding a sling (gold must be included) */ static NEARDATA const char bullets[] = - { ALLOW_COUNT, GOLD_CLASS, ALL_CLASSES, GEM_CLASS, 0 }; + { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0 }; + +struct obj *thrownobj = 0; /* tracks an object until it lands */ extern boolean notonhead; /* for long worms */ @@ -44,7 +46,7 @@ /* ask "in what direction?" */ #ifndef GOLDOBJ if (!getdir((char *)0)) { - if (obj->oclass == GOLD_CLASS) { + if (obj->oclass == COIN_CLASS) { u.ugold += obj->quan; flags.botl = 1; dealloc_obj(obj); @@ -52,7 +54,7 @@ return(0); } - if(obj->oclass == GOLD_CLASS) return(throw_gold(obj)); + if(obj->oclass == COIN_CLASS) return(throw_gold(obj)); #else if (!getdir((char *)0)) { /* obj might need to be merged back into the singular gold object */ @@ -69,7 +71,7 @@ If the money is in quiver, throw one coin at a time, possibly using a sling. */ - if(obj->oclass == GOLD_CLASS && obj != uquiver) return(throw_gold(obj)); + if(obj->oclass == COIN_CLASS && obj != uquiver) return(throw_gold(obj)); #endif if(!canletgo(obj,"throw")) @@ -167,8 +169,8 @@ otmp = splitobj(obj, 1L); } else { otmp = obj; - if (otmp->owornmask && otmp != uball) - remove_worn_item(otmp); + if (otmp->owornmask) + remove_worn_item(otmp, FALSE); } freeinv(otmp); throwit(otmp, wep_mask, twoweap); @@ -215,7 +217,7 @@ static void autoquiver() { - register struct obj *otmp, *oammo = 0, *omissile = 0, *omisc = 0; + struct obj *otmp, *oammo = 0, *omissile = 0, *omisc = 0, *altammo = 0; if (uquiver) return; @@ -233,6 +235,8 @@ objects[otmp->otyp].oc_material == GLASS)) { if (uslinging()) oammo = otmp; + else if (ammo_and_launcher(otmp, uswapwep)) + altammo = otmp; else if (!omisc) omisc = otmp; } else if (otmp->oclass == GEM_CLASS) { @@ -242,6 +246,8 @@ if (ammo_and_launcher(otmp, uwep)) /* Ammo matched with launcher (bow and arrow, crossbow and bolt) */ oammo = otmp; + else if (ammo_and_launcher(otmp, uswapwep)) + altammo = otmp; else /* Mismatched ammo (no better than an ordinary weapon) */ omisc = otmp; @@ -263,6 +269,8 @@ setuqwep(oammo); else if (omissile) setuqwep(omissile); + else if (altammo) + setuqwep(altammo); else if (omisc) setuqwep(omisc); @@ -437,11 +445,13 @@ if (!isok(x,y)) { You_feel("the spirits holding you back."); return FALSE; + } else if (!in_out_region(x, y)) { + return FALSE; } if (!Passes_walls || !(may_pass = may_passwall(x, y))) { if (IS_ROCK(levl[x][y].typ) || closed_door(x,y)) { - char *s; + const char *s; pline("Ouch!"); if (IS_TREE(levl[x][y].typ)) @@ -469,6 +479,17 @@ losehp(rnd(2+*range), "touching the edge of the universe", KILLED_BY); return FALSE; } + if ((u.ux - x) && (u.uy - y) && + bad_rock(youmonst.data,u.ux,y) && bad_rock(youmonst.data,x,u.uy)) { + boolean too_much = (invent && (inv_weight() + weight_cap() > 600)); + /* Move at a diagonal. */ + if (bigmonst(youmonst.data) || too_much) { + You("%sget forcefully wedged into a crevice.", + too_much ? "and all your belongings " : ""); + losehp(rnd(2+*range), "wedging into a narrow crevice", KILLED_BY); + return FALSE; + } + } } if ((mon = m_at(x, y)) != 0) { @@ -536,7 +557,7 @@ /* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially * rather than just stopping before. */ - if (goodpos(x, y, mon) && m_in_out_region(mon, x, y)) { + if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) { remove_monster(mon->mx, mon->my); newsym(mon->mx, mon->my); place_monster(mon, x, y); @@ -863,6 +884,8 @@ u.dz = 1; } + thrownobj = obj; + if(u.uswallow) { mon = u.ustuck; bhitpos.x = mon->mx; @@ -882,6 +905,7 @@ } else { hitfloor(obj); } + thrownobj = (struct obj*)0; return; } else if(obj->otyp == BOOMERANG && !Underwater) { @@ -896,6 +920,7 @@ setworn(obj, wep_mask); u.twoweap = twoweap; } + thrownobj = (struct obj*)0; return; } } else { @@ -953,8 +978,10 @@ boolean obj_gone; if (mon->isshk && - obj->where == OBJ_MINVENT && obj->ocarry == mon) + obj->where == OBJ_MINVENT && obj->ocarry == mon) { + thrownobj = (struct obj*)0; return; /* alert shk caught it */ + } (void) snuff_candle(obj); notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my); obj_gone = thitmonst(mon, obj); @@ -1004,12 +1031,16 @@ body_part(ARM)); (void) artifact_hit((struct monst *)0, &youmonst, obj, &dmg, 0); - losehp(dmg, xname(obj), KILLED_BY); + losehp(dmg, xname(obj), + obj_is_pname(obj) ? KILLED_BY : KILLED_BY_AN); } - if (ship_object(obj, u.ux, u.uy, FALSE)) + if (ship_object(obj, u.ux, u.uy, FALSE)) { + thrownobj = (struct obj*)0; return; + } dropy(obj); } + thrownobj = (struct obj*)0; return; } @@ -1032,11 +1063,15 @@ if(*u.ushops) check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE); (void) mpickobj(mon, obj); /* may merge and free obj */ + thrownobj = (struct obj*)0; return; } (void) snuff_candle(obj); - if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) + if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) { + thrownobj = (struct obj*)0; return; + } + thrownobj = (struct obj*)0; place_object(obj, bhitpos.x, bhitpos.y); if(*u.ushops && obj != uball) check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE); @@ -1480,19 +1515,17 @@ /* * Unconditionally break an object. Assumes all resistance checks * and break messages have been delivered prior to getting here. - * This routine assumes the cause is the hero if heros_fault is TRUE. - * */ STATIC_OVL void -breakobj(obj, x, y, heros_fault, from_invent) +breakobj(obj, x, y, hero_caused, from_invent) struct obj *obj; xchar x, y; /* object location (ox, oy may not be right) */ -boolean heros_fault; +boolean hero_caused; /* is this the hero's fault? */ boolean from_invent; { switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) { case MIRROR: - if (heros_fault) + if (hero_caused) change_luck(-2); break; case POT_WATER: /* really, all potions */ @@ -1519,11 +1552,11 @@ break; case EGG: /* breaking your own eggs is bad luck */ - if (heros_fault && obj->spe && obj->corpsenm >= LOW_PM) + if (hero_caused && obj->spe && obj->corpsenm >= LOW_PM) change_luck((schar) -min(obj->quan, 5L)); break; } - if (heros_fault) { + if (hero_caused) { if (from_invent) { if (*u.ushops) check_shop_obj(obj, x, y, TRUE); @@ -1570,6 +1603,7 @@ case POT_WATER: /* really, all potions */ case EGG: case CREAM_PIE: + case MELON: case ACID_VENOM: case BLINDING_VENOM: return 1; @@ -1607,6 +1641,7 @@ (obj->quan==1) ? "s" : "", to_pieces); break; case EGG: + case MELON: pline("Splat!"); break; case CREAM_PIE: @@ -1633,6 +1668,11 @@ register struct monst *mon; if(!u.dx && !u.dy && !u.dz) { +#ifndef GOLDOBJ + u.ugold += obj->quan; + flags.botl = 1; + dealloc_obj(obj); +#endif You("cannot throw gold at yourself."); return(0); } diff -Naurd ../nethack-3.4.0/src/drawing.c ./src/drawing.c --- ../nethack-3.4.0/src/drawing.c Wed Mar 20 23:43:04 2002 +++ ./src/drawing.c Mon Feb 24 15:25:05 2003 @@ -46,10 +46,10 @@ VENOM_SYM }; -const char *invisexplain = "remembered, unseen, creature"; +const char invisexplain[] = "remembered, unseen, creature"; /* Object descriptions. Used in do_look(). */ -const char *objexplain[] = { /* these match def_oc_syms, above */ +const char * const objexplain[] = { /* these match def_oc_syms, above */ /* 0*/ 0, "strange object", "weapon", @@ -71,7 +71,7 @@ }; /* Object class names. Used in object_detect(). */ -const char *oclass_names[] = { +const char * const oclass_names[] = { /* 0*/ 0, "illegal objects", "weapons", @@ -161,7 +161,7 @@ * for blessed genocide, so no text should wholly contain any later * text. They should also always contain obvious names (eg. cat/feline). */ -const char *monexplain[MAXMCLASSES] = { +const char * const monexplain[MAXMCLASSES] = { 0, "ant or other insect", "blob", "cockatrice", "dog or other canine", "eye or sphere", "cat or other feline", @@ -169,7 +169,7 @@ "jelly", "kobold", "leprechaun", "mimic", "nymph", "orc", "piercer", "quadruped", "rodent", - "spider", "trapper or lurker above", "unicorn or horse", + "arachnid or centipede", "trapper or lurker above", "unicorn or horse", "vortex", "worm", "xan or other mythical/fantastic insect", "light", "zruty", @@ -181,7 +181,7 @@ "pudding or ooze", "quantum mechanic", "rust monster or disenchanter", "snake", "troll", "umber hulk", "vampire", "wraith", "xorn", - "yeti, ape or other large beast", "zombie", + "apelike creature", "zombie", "human or elf", "ghost", "golem", "major demon", "sea monster", "lizard", diff -Naurd ../nethack-3.4.0/src/dungeon.c ./src/dungeon.c --- ../nethack-3.4.0/src/dungeon.c Wed Mar 20 23:43:04 2002 +++ ./src/dungeon.c Mon Feb 24 15:25:05 2003 @@ -486,6 +486,9 @@ new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE); new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE); new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4); + if (!new_level->flags.align) + new_level->flags.align = + ((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4); new_level->rndlevs = tlevel->rndlevs; new_level->next = (s_level *) 0; diff -Naurd ../nethack-3.4.0/src/eat.c ./src/eat.c --- ../nethack-3.4.0/src/eat.c Wed Mar 20 23:43:04 2002 +++ ./src/eat.c Mon Feb 24 15:25:05 2003 @@ -33,6 +33,7 @@ STATIC_DCL int FDECL(eatcorpse, (struct obj *)); STATIC_DCL void FDECL(start_eating, (struct obj *)); STATIC_DCL void FDECL(fprefx, (struct obj *)); +STATIC_DCL void FDECL(accessory_has_effect, (struct obj *)); STATIC_DCL void FDECL(fpostfx, (struct obj *)); STATIC_DCL int NDECL(bite); STATIC_DCL int FDECL(edibility_prompts, (struct obj *)); @@ -70,7 +71,7 @@ /* Gold must come first for getobj(). */ STATIC_OVL NEARDATA const char allobj[] = { - GOLD_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS, + COIN_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS, FOOD_CLASS, TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0 }; @@ -253,7 +254,7 @@ */ if(food) { You("choke over your %s.", foodword(food)); - if (food->oclass == GOLD_CLASS) { + if (food->oclass == COIN_CLASS) { killer = "a very rich meal"; } else { killer = food_xname(food, FALSE); @@ -316,8 +317,7 @@ if (!otmp->oeaten) { if(((!carried(otmp) && costly_spot(otmp->ox, otmp->oy) && !otmp->no_charge) - || otmp->unpaid) && - (otmp->otyp == CORPSE || objects[otmp->otyp].oc_delay > 1)) { + || otmp->unpaid)) { /* create a dummy duplicate to put on bill */ verbalize("You bit it, you bought it!"); bill_dummy_object(otmp); @@ -770,22 +770,41 @@ register int pm; { register int tmp = 0; + boolean catch_lycanthropy = FALSE; /* in case `afternmv' didn't get called for previously mimicking gold, clean up now to avoid `eatmbuf' memory leak */ if (eatmbuf) (void)eatmdone(); switch(pm) { + case PM_NEWT: + /* MRKR: "eye of newt" may give small magical energy boost */ + if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) { + int old_uen = u.uen; + u.uen += rnd(3); + if (u.uen > u.uenmax) { + if (!rn2(3)) u.uenmax++; + u.uen = u.uenmax; + } + if (old_uen != u.uen) { + You_feel("a mild buzz."); + flags.botl = 1; + } + } + break; case PM_WRAITH: pluslvl(FALSE); break; case PM_HUMAN_WERERAT: + catch_lycanthropy = TRUE; u.ulycn = PM_WERERAT; break; case PM_HUMAN_WEREJACKAL: + catch_lycanthropy = TRUE; u.ulycn = PM_WEREJACKAL; break; case PM_HUMAN_WEREWOLF: + catch_lycanthropy = TRUE; u.ulycn = PM_WEREWOLF; break; case PM_NURSE: @@ -819,22 +838,25 @@ /* fall into next case */ case PM_SMALL_MIMIC: tmp += 20; - if (youmonst.data->mlet != S_MIMIC) { + if (youmonst.data->mlet != S_MIMIC && !Unchanging) { char buf[BUFSZ]; - You_cant("resist the temptation to mimic a pile of gold."); + You_cant("resist the temptation to mimic %s.", + Hallucination ? "an orange" : "a pile of gold"); #ifdef STEED /* A pile of gold can't ride. */ if (u.usteed) dismount_steed(DISMOUNT_FELL); #endif nomul(-tmp); - Sprintf(buf, "You now prefer mimicking %s again.", - an(Upolyd ? youmonst.data->mname : urace.noun)); + Sprintf(buf, Hallucination ? + "You suddenly dread being peeled and mimick %s again!" : + "You now prefer mimicking %s again.", + an(Upolyd ? youmonst.data->mname : urace.noun)); eatmbuf = strcpy((char *) alloc(strlen(buf) + 1), buf); nomovemsg = eatmbuf; afternmv = eatmdone; /* ??? what if this was set before? */ youmonst.m_ap_type = M_AP_OBJECT; - youmonst.mappearance = GOLD_PIECE; + youmonst.mappearance = Hallucination ? ORANGE : GOLD_PIECE; newsym(u.ux,u.uy); curs_on_u(); /* make gold symbol show up now */ @@ -934,6 +956,14 @@ } break; } + + if (catch_lycanthropy && defends(AD_WERE, uwep)) { + if (!touch_artifact(uwep, &youmonst)) { + dropx(uwep); + uwepgone(); + } + } + return; } @@ -1037,7 +1067,7 @@ } else { if (tin.tin->cursed) pline("It contains some decaying%s%s substance.", - Blind ? "" : " ", Blind ? "" : hcolor(green)); + Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN)); else pline("It contains spinach."); @@ -1309,8 +1339,12 @@ } +/* + * called on "first bite" of (non-corpse) food. + * used for non-rotten non-tin non-corpse food + */ STATIC_OVL void -fprefx(otmp) /* called on "first bite" of (non-corpse) food */ +fprefx(otmp) struct obj *otmp; { switch(otmp->otyp) { @@ -1389,33 +1423,14 @@ Hallucination ? "gnarly!" : "delicious!"); break; } +} - /* KMH, conduct */ - switch (objects[otmp->otyp].oc_material) { - case WAX: /* let's assume bees' wax */ - u.uconduct.unvegan++; - break; - - case FLESH: - if (otmp->otyp == EGG) { - u.uconduct.unvegan++; - break; - } - case LEATHER: - case BONE: - case DRAGON_HIDE: - u.uconduct.unvegan++; - violated_vegetarian(); - break; - - default: - if (otmp->otyp == PANCAKE || - otmp->otyp == FORTUNE_COOKIE || /* eggs */ - otmp->otyp == CREAM_PIE || otmp->otyp == CANDY_BAR || /* milk */ - otmp->otyp == LUMP_OF_ROYAL_JELLY) - u.uconduct.unvegan++; - break; - } +STATIC_OVL void +accessory_has_effect(otmp) +struct obj *otmp; +{ + pline("Magic spreads through your body as you digest the %s.", + otmp->oclass == RING_CLASS ? "ring" : "amulet"); } STATIC_OVL void @@ -1433,14 +1448,13 @@ if (u.uhp <= 0) return; /* died from sink fall */ } otmp->known = otmp->dknown = 1; /* by taste */ - if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) + if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) { switch (otmp->otyp) { default: if (!objects[typ].oc_oprop) break; /* should never happen */ if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE)) - pline("Magic spreads through your body as you digest the %s.", - otmp->oclass == RING_CLASS ? "ring" : "amulet"); + accessory_has_effect(otmp); u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE; @@ -1479,35 +1493,44 @@ } break; case RIN_ADORNMENT: + accessory_has_effect(otmp); if (adjattrib(A_CHA, otmp->spe, -1)) makeknown(typ); break; case RIN_GAIN_STRENGTH: + accessory_has_effect(otmp); if (adjattrib(A_STR, otmp->spe, -1)) makeknown(typ); break; case RIN_GAIN_CONSTITUTION: + accessory_has_effect(otmp); if (adjattrib(A_CON, otmp->spe, -1)) makeknown(typ); break; case RIN_INCREASE_ACCURACY: + accessory_has_effect(otmp); u.uhitinc += otmp->spe; break; case RIN_INCREASE_DAMAGE: + accessory_has_effect(otmp); u.udaminc += otmp->spe; break; case RIN_PROTECTION: + accessory_has_effect(otmp); HProtection |= FROMOUTSIDE; u.ublessed += otmp->spe; flags.botl = 1; break; case RIN_FREE_ACTION: /* Give sleep resistance instead */ + if (!(HSleep_resistance & FROMOUTSIDE)) + accessory_has_effect(otmp); if (!Sleep_resistance) You_feel("wide awake."); HSleep_resistance |= FROMOUTSIDE; break; case AMULET_OF_CHANGE: + accessory_has_effect(otmp); makeknown(typ); change_sex(); You("are suddenly very %s!", @@ -1515,12 +1538,16 @@ flags.botl = 1; break; case AMULET_OF_STRANGULATION: /* bad idea! */ + /* no message--this gives no permanent effect */ choke(otmp); break; case AMULET_OF_RESTFUL_SLEEP: /* another bad idea! */ + if (!(HSleeping & FROMOUTSIDE)) + accessory_has_effect(otmp); HSleeping = FROMOUTSIDE | rnd(100); break; - case RIN_SUSTAIN_ABILITY: + case RIN_SUSTAIN_ABILITY: + case AMULET_OF_UNCHANGING: case AMULET_OF_LIFE_SAVING: case AMULET_OF_REFLECTION: /* nice try */ /* can't eat Amulet of Yendor or fakes, @@ -1528,6 +1555,7 @@ */ break; } + } } STATIC_OVL void @@ -1538,7 +1566,7 @@ lesshungry(victual.nmod); victual.piece = (struct obj *)0; victual.eating = 0; - if (otmp->oclass == GOLD_CLASS) { + if (otmp->oclass == COIN_CLASS) { #ifdef GOLDOBJ if (carried(otmp)) useupall(otmp); @@ -1674,24 +1702,24 @@ ability to detect food that is unfit for consumption or dangerous and avoid it. */ - char buf[BUFSZ], foodsmell[BUFSZ]; - char *eat_it_anyway = "Eat it anyway?"; - boolean cadaver = (otmp->otyp == CORPSE); - boolean stoneorslime = FALSE; - int material = objects[otmp->otyp].oc_material; + char buf[BUFSZ], foodsmell[BUFSZ], + it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ]; + boolean cadaver = (otmp->otyp == CORPSE), + stoneorslime = FALSE; + int material = objects[otmp->otyp].oc_material, + mnum = otmp->corpsenm; long rotted = 0L; - int mnum; - -#ifdef GCC_WARN - mnum = 0; -#endif Strcpy(foodsmell, Tobjnam(otmp, "smell")); + Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they"); + Sprintf(eat_it_anyway, "Eat %s anyway?", + (otmp->quan == 1L) ? "it" : "one"); + if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) { - mnum = otmp->corpsenm; /* These checks must match those in eatcorpse() */ - stoneorslime = (touch_petrifies(&mons[mnum]) && - !Stone_resistance && !poly_when_stoned(youmonst.data)); + stoneorslime = (touch_petrifies(&mons[mnum]) && + !Stone_resistance && + !poly_when_stoned(youmonst.data)); if (mnum == PM_GREEN_SLIME) stoneorslime = (!Unchanging && @@ -1717,28 +1745,28 @@ if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) { /* Tainted meat */ - Sprintf(buf, "%s like it could be tainted! %s", - foodsmell, eat_it_anyway); + Sprintf(buf, "%s like %s could be tainted! %s", + foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (stoneorslime) { - Sprintf(buf, "%s like it could be something very dangerous! %s", - foodsmell, eat_it_anyway); + Sprintf(buf, "%s like %s could be something very dangerous! %s", + foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (otmp->orotten || (cadaver && rotted > 3L)) { /* Rotten */ - Sprintf(buf, "%s like it could be rotten! %s", - foodsmell, eat_it_anyway); + Sprintf(buf, "%s like %s could be rotten! %s", + foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) { /* poisonous */ - Sprintf(buf, "%s like it might be poisonous! %s", - foodsmell, eat_it_anyway); + Sprintf(buf, "%s like %s might be poisonous! %s", + foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } @@ -1755,8 +1783,8 @@ if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } - if (Upolyd && - (u.umonnum == PM_RUST_MONSTER && is_metallic(otmp) && otmp->oerodeproof)) { + if (Upolyd && u.umonnum == PM_RUST_MONSTER && + is_metallic(otmp) && otmp->oerodeproof) { Sprintf(buf, "%s disgusting to you right now. %s", foodsmell, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; @@ -1777,7 +1805,8 @@ else return 2; } if (!u.uconduct.unvegetarian && - ((material == LEATHER || material == BONE || material == DRAGON_HIDE) || + ((material == LEATHER || material == BONE || + material == DRAGON_HIDE) || (cadaver && !vegetarian(&mons[mnum])))) { Sprintf(buf, "%s unfamiliar to you. %s", foodsmell, eat_it_anyway); @@ -1787,8 +1816,8 @@ if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) { /* Tainted meat with Sick_resistance */ - Sprintf(buf, "%s like it could be tainted! %s", - foodsmell, eat_it_anyway); + Sprintf(buf, "%s like %s could be tainted! %s", + foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } @@ -1876,7 +1905,7 @@ victual.canchoke = (u.uhs == SATIATED); /* Note: gold weighs 1 pt. for each 1000 pieces (see */ /* pickup.c) so gold and non-gold is consistent. */ - if (otmp->oclass == GOLD_CLASS) + if (otmp->oclass == COIN_CLASS) basenutrit = ((otmp->quan > 200000L) ? 2000 : (int)(otmp->quan/100L)); else if(otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) @@ -1887,11 +1916,12 @@ victual.eating = TRUE; /* needed for lesshungry() */ material = objects[otmp->otyp].oc_material; - if (material == LEATHER || material == BONE || material == DRAGON_HIDE) { - u.uconduct.unvegan++; - violated_vegetarian(); + if (material == LEATHER || + material == BONE || material == DRAGON_HIDE) { + u.uconduct.unvegan++; + violated_vegetarian(); } else if (material == WAX) - u.uconduct.unvegan++; + u.uconduct.unvegan++; u.uconduct.food++; if (otmp->cursed) @@ -1906,7 +1936,7 @@ You("seem unaffected by the poison."); } else if (!otmp->cursed) pline("This %s is delicious!", - otmp->oclass == GOLD_CLASS ? foodword(otmp) : + otmp->oclass == COIN_CLASS ? foodword(otmp) : singular(otmp, xname)); eatspecial(); @@ -1956,6 +1986,26 @@ /* if not used up, eatcorpse sets up reqtime and may modify * oeaten */ } else { + /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE. These are + * all handled in the != FOOD_CLASS case, above */ + switch (objects[otmp->otyp].oc_material) { + case FLESH: + u.uconduct.unvegan++; + if (otmp->otyp != EGG) { + violated_vegetarian(); + } + break; + + default: + if (otmp->otyp == PANCAKE || + otmp->otyp == FORTUNE_COOKIE || /* eggs */ + otmp->otyp == CREAM_PIE || + otmp->otyp == CANDY_BAR || /* milk */ + otmp->otyp == LUMP_OF_ROYAL_JELLY) + u.uconduct.unvegan++; + break; + } + victual.reqtime = objects[otmp->otyp].oc_delay; if (otmp->otyp != FORTUNE_COOKIE && (otmp->cursed || @@ -2367,7 +2417,7 @@ for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) { if(corpsecheck ? (otmp->otyp==CORPSE && (corpsecheck == 1 || tinnable(otmp))) : - feeding ? (otmp->oclass != GOLD_CLASS && is_edible(otmp)) : + feeding ? (otmp->oclass != COIN_CLASS && is_edible(otmp)) : otmp->oclass==FOOD_CLASS) { Sprintf(qbuf, "There %s %s here; %s %s?", otense(otmp, "are"), diff -Naurd ../nethack-3.4.0/src/end.c ./src/end.c --- ../nethack-3.4.0/src/end.c Wed Mar 20 23:43:05 2002 +++ ./src/end.c Mon Feb 24 15:25:05 2003 @@ -18,7 +18,7 @@ struct valuable_data { long count; int typ; }; -struct valuable_data +static struct valuable_data gems[LAST_GEM+1 - FIRST_GEM + 1], /* 1 extra for glass */ amulets[LAST_AMULET+1 - FIRST_AMULET]; @@ -37,12 +37,11 @@ STATIC_DCL void FDECL(disclose,(int,BOOLEAN_P)); STATIC_DCL void FDECL(get_valuables, (struct obj *)); STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *,int)); -STATIC_DCL void FDECL(add_artifact_score, (struct obj *)); -STATIC_DCL void FDECL(display_artifact_score, (struct obj *,winid)); +STATIC_DCL void FDECL(artifact_score, (struct obj *,BOOLEAN_P,winid)); STATIC_DCL void FDECL(savelife, (int)); -STATIC_DCL void FDECL(list_vanquished, (int, BOOLEAN_P)); -STATIC_DCL void FDECL(list_genocided, (int, BOOLEAN_P)); -STATIC_DCL boolean FDECL(should_query_disclose_option, (int, int*)); +STATIC_DCL void FDECL(list_vanquished, (CHAR_P,BOOLEAN_P)); +STATIC_DCL void FDECL(list_genocided, (CHAR_P,BOOLEAN_P)); +STATIC_DCL boolean FDECL(should_query_disclose_option, (int,char *)); #if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2) extern void FDECL(nethack_exit,(int)); @@ -81,8 +84,7 @@ "quit", "escaped", "ascended" }; -extern const char *killed_by_prefix[]; - +extern const char * const killed_by_prefix[]; /* from topten.c */ /*ARGSUSED*/ void @@ -186,6 +188,7 @@ You("die..."); mark_synch(); /* flush buffered screen output */ buf[0] = '\0'; + killer_format = KILLED_BY_AN; /* "killed by the high priest of Crom" is okay, "killed by the high priest" alone isn't */ if ((mtmp->data->geno & G_UNIQ) != 0 && !(mtmp->data == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) { @@ -193,18 +196,19 @@ Strcat(buf, "the "); killer_format = KILLED_BY; } + /* _the_ ghost of Dudley */ + if (mtmp->data == &mons[PM_GHOST] && mtmp->mnamelth) { + Strcat(buf, "the "); + killer_format = KILLED_BY; + } if (mtmp->minvis) Strcat(buf, "invisible "); if (distorted) Strcat(buf, "hallucinogen-distorted "); if(mtmp->data == &mons[PM_GHOST]) { - char *gn = NAME(mtmp); - if (!distorted && !mtmp->minvis && *gn) { - Strcat(buf, "the "); - killer_format = KILLED_BY; - } - Sprintf(eos(buf), (*gn ? "ghost of %s" : "ghost%s"), gn); + Strcat(buf, "ghost"); + if (mtmp->mnamelth) Sprintf(eos(buf), " of %s", NAME(mtmp)); } else if(mtmp->isshk) { Sprintf(eos(buf), "%s %s, the shopkeeper", (mtmp->female ? "Ms." : "Mr."), shkname(mtmp)); @@ -290,36 +307,39 @@ STATIC_OVL boolean should_query_disclose_option(category, defquery) int category; -int *defquery; +char *defquery; { - int idx; - char *dop = index(disclosure_options, category); - if (dop && defquery) { - idx = (dop - disclosure_options) / sizeof(char); - if (idx < 0 || idx > (NUM_DISCLOSURE_OPTIONS - 1)) { - impossible( - "should_query_disclose_option: bad disclosure index %d %c", - idx, category); - *defquery = DISCLOSE_PROMPT_DEFAULT_YES; - return TRUE; - } - if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) { - *defquery = 'y'; - return FALSE; - } else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) { - *defquery = 'n'; - return FALSE; - } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) { - *defquery = 'y'; - return TRUE; - } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_NO) { - *defquery = 'n'; - return TRUE; - } + int idx; + char *dop = index(disclosure_options, category); + + if (dop && defquery) { + idx = dop - disclosure_options; + if (idx < 0 || idx > (NUM_DISCLOSURE_OPTIONS - 1)) { + impossible( + "should_query_disclose_option: bad disclosure index %d %c", + idx, category); + *defquery = DISCLOSE_PROMPT_DEFAULT_YES; + return TRUE; } - if (defquery)impossible("should_query_disclose_option: bad category %c", category); - else impossible("should_query_disclose_option: null defquery"); - return TRUE; + if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) { + *defquery = 'y'; + return FALSE; + } else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) { + *defquery = 'n'; + return FALSE; + } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) { + *defquery = 'y'; + return TRUE; + } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_NO) { + *defquery = 'n'; + return TRUE; + } + } + if (defquery) + impossible("should_query_disclose_option: bad category %c", category); + else + impossible("should_query_disclose_option: null defquery"); + return TRUE; } STATIC_OVL void @@ -327,9 +347,8 @@ int how; boolean taken; { - char c = 0; + char c = 0, defquery; char qbuf[QBUFSZ]; - int defquery; boolean ask; if (invent) { @@ -341,12 +360,10 @@ ask = should_query_disclose_option('i', &defquery); if (!done_stopprint) { - if (ask) - c = yn_function(qbuf, ynqchars, defquery); - if ((!ask && defquery == 'y') || (ask && c == 'y')) { - /* New dump format by maartenj@cs.vu.nl */ + c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery; + if (c == 'y') { struct obj *obj; - + for (obj = invent; obj; obj = obj->nobj) { makeknown(obj->otyp); obj->known = obj->bknown = obj->dknown = obj->rknown = 1; @@ -354,17 +371,17 @@ (void) display_inventory((char *)0, TRUE); container_contents(invent, TRUE, TRUE); } - if (ask && c == 'q') done_stopprint++; + if (c == 'q') done_stopprint++; } } - ask = should_query_disclose_option('a', &defquery); + ask = should_query_disclose_option('a', &defquery); if (!done_stopprint) { - if (ask) - c = yn_function("Do you want to see your attributes?",ynqchars, defquery); - if ((!ask && defquery == 'y') || (ask && c == 'y')) + c = ask ? yn_function("Do you want to see your attributes?", + ynqchars, defquery) : defquery; + if (c == 'y') enlightenment(how >= PANICKED ? 1 : 2); /* final */ - if (ask && c == 'q') done_stopprint++; + if (c == 'q') done_stopprint++; } ask = should_query_disclose_option('v', &defquery); @@ -377,11 +394,11 @@ ask = should_query_disclose_option('c', &defquery); if (!done_stopprint) { - if (ask) - c = yn_function("Do you want to see your conduct?",ynqchars,defquery); - if ((!ask && defquery == 'y') || (ask && c == 'y')) + c = ask ? yn_function("Do you want to see your conduct?", + ynqchars, defquery) : defquery; + if (c == 'y') show_conduct(how >= PANICKED ? 1 : 2); - if (ask && c == 'q') done_stopprint++; + if (c == 'q') done_stopprint++; } } @@ -471,52 +488,41 @@ return; } +/* called twice; first to calculate total, then to list relevant items */ STATIC_OVL void -add_artifact_score(list) -struct obj *list; -{ - struct obj *otmp; - - for (otmp = list; otmp; otmp = otmp->nobj) - if (otmp->oartifact || - otmp->otyp == BELL_OF_OPENING || - otmp->otyp == SPE_BOOK_OF_THE_DEAD || - otmp->otyp == CANDELABRUM_OF_INVOCATION) { - u.urexp += (arti_cost(otmp) * 5 / 2); - if (Has_contents(otmp)) - add_artifact_score(otmp->cobj); - } -} - -STATIC_OVL void -display_artifact_score(list,endwin) +artifact_score(list, counting, endwin) struct obj *list; +boolean counting; /* true => add up points; false => display them */ winid endwin; { char pbuf[BUFSZ]; struct obj *otmp; + long value, points; + short dummy; /* object type returned by artifact_name() */ for (otmp = list; otmp; otmp = otmp->nobj) { if (otmp->oartifact || otmp->otyp == BELL_OF_OPENING || otmp->otyp == SPE_BOOK_OF_THE_DEAD || otmp->otyp == CANDELABRUM_OF_INVOCATION) { - short dummy; - - makeknown(otmp->otyp); - otmp->known = otmp->bknown = otmp->dknown = - otmp->rknown = 1; - /* assumes artifacts don't have quan>1 */ - Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)", - the_unique_obj(otmp) ? "The " : "", - otmp->oartifact ? artifact_name(xname(otmp), &dummy) : - OBJ_NAME(objects[otmp->otyp]), - arti_cost(otmp), currency(2L), - arti_cost(otmp) * 5 / 2); - putstr(endwin, 0, pbuf); + value = arti_cost(otmp); /* zorkmid value */ + points = value * 5 / 2; /* score value */ + if (counting) { + u.urexp += points; + } else { + makeknown(otmp->otyp); + otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1; + /* assumes artifacts don't have quan > 1 */ + Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)", + the_unique_obj(otmp) ? "The " : "", + otmp->oartifact ? artifact_name(xname(otmp), &dummy) : + OBJ_NAME(objects[otmp->otyp]), + value, currency(value), points); + putstr(endwin, 0, pbuf); + } } if (Has_contents(otmp)) - display_artifact_score(otmp->cobj,endwin); + artifact_score(otmp->cobj, counting, endwin); } } @@ -532,6 +538,19 @@ struct obj *corpse = (struct obj *)0; long umoney; + if (how == TRICKED) { + if (killer) { + paniclog("trickery", killer); + killer = 0; + } +#ifdef WIZARD + if (wizard) { + You("are a very tricky wizard, it seems."); + return; + } +#endif + } + /* kilbuf: used to copy killer in case it comes from something like * xname(), which would otherwise get overwritten when we call * xname() when listing possessions @@ -544,12 +563,7 @@ killer_format = KILLED_BY; Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer)); killer = kilbuf; -#ifdef WIZARD - if (wizard && how == TRICKED) { - You("are a very tricky wizard, it seems."); - return; - } -#endif + if (how < PANICKED) u.umortality++; if (Lifesaved && (how <= GENOCIDED)) { pline("But wait..."); @@ -630,7 +644,17 @@ u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */ else if (u.ugrave_arise == NON_PM && !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) { - corpse = mk_named_object(CORPSE, &mons[u.umonnum], + int mnum = u.umonnum; + + if (!Upolyd) { + /* Base corpse on race when not poly'd since original + * u.umonnum is based on role, and all role monsters + * are human. + */ + mnum = (flags.female && urace.femalenum != NON_PM) ? + urace.femalenum : urace.malenum; + } + corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, plname); Sprintf(pbuf, "%s, %s%s", plname, killer_format == NO_KILLER_PREFIX ? "" : @@ -654,7 +678,7 @@ if (how != PANICKED) { /* these affect score and/or bones, but avoid them during panic */ - taken = paybill(how != QUIT); + taken = paybill((how == ESCAPED) ? -1 : (how != QUIT)); paygd(); clearpriests(); } else taken = FALSE; /* lint; assert( !bones_ok ); */ @@ -724,7 +748,8 @@ if(!done_stopprint || flags.tombstone) endwin = create_nhwindow(NHW_TEXT); - if(how < GENOCIDED && flags.tombstone) outrip(endwin, how); + if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR) + outrip(endwin, how); } else done_stopprint = 1; /* just avoid any more output */ @@ -769,7 +794,8 @@ u.urexp += val->list[i].count * (long)objects[val->list[i].typ].oc_cost; - add_artifact_score(invent); + /* count the points for artifacts */ + artifact_score(invent, TRUE, endwin); keepdogs(TRUE); viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */ @@ -797,7 +823,7 @@ } if (!done_stopprint) - display_artifact_score(invent,endwin); + artifact_score(invent, FALSE, endwin); /* list artifacts */ /* list valuables here */ for (val = valuables; val->list; val++) { @@ -942,7 +968,7 @@ STATIC_OVL void list_vanquished(defquery, ask) -int defquery; +char defquery; boolean ask; { register int i, lev; @@ -963,11 +989,10 @@ * includes all dead monsters, not just those killed by the player */ if (ntypes != 0) { - if (ask) - c = yn_function("Do you want an account of creatures vanquished?", - ynqchars, defquery); - if (ask && c == 'q') done_stopprint++; - if ((!ask && defquery == 'y') || (ask && c == 'y')) { + c = ask ? yn_function("Do you want an account of creatures vanquished?", + ynqchars, defquery) : defquery; + if (c == 'q') done_stopprint++; + if (c == 'y') { klwin = create_nhwindow(NHW_MENU); putstr(klwin, 0, "Vanquished creatures:"); putstr(klwin, 0, ""); @@ -982,11 +1007,11 @@ mons[i].mname); if (nkilled > 1) { switch (nkilled) { - case 2: Sprintf(eos(buf)," (twice)"); break; - case 3: Sprintf(eos(buf)," (thrice)"); break; - default: Sprintf(eos(buf)," (%d time%s)", - nkilled, plur(nkilled)); - break; + case 2: Sprintf(eos(buf)," (twice)"); break; + case 3: Sprintf(eos(buf)," (thrice)"); break; + default: Sprintf(eos(buf)," (%d time%s)", + nkilled, plur(nkilled)); + break; } } } else { @@ -1029,7 +1054,7 @@ STATIC_OVL void list_genocided(defquery, ask) -int defquery; +char defquery; boolean ask; { register int i; @@ -1042,11 +1067,10 @@ /* genocided species list */ if (ngenocided != 0) { - if (ask) - c = yn_function("Do you want a list of species genocided?", - ynqchars, defquery); - if (ask && c == 'q') done_stopprint++; - if ((!ask && defquery == 'y') || (ask && c == 'y')) { + c = ask ? yn_function("Do you want a list of species genocided?", + ynqchars, defquery) : defquery; + if (c == 'q') done_stopprint++; + if (c == 'y') { klwin = create_nhwindow(NHW_MENU); putstr(klwin, 0, "Genocided species:"); putstr(klwin, 0, ""); diff -Naurd ../nethack-3.4.0/src/engrave.c ./src/engrave.c --- ../nethack-3.4.0/src/engrave.c Wed Mar 20 23:43:05 2002 +++ ./src/engrave.c Mon Feb 24 15:25:05 2003 @@ -370,7 +370,7 @@ ep->engr_txt = (char *)(ep + 1); Strcpy(ep->engr_txt, s); /* engraving Elbereth shows wisdom */ - if(!strcmp(s, "Elbereth")) exercise(A_WIS, TRUE); + if (!in_mklev && !strcmp(s, "Elbereth")) exercise(A_WIS, TRUE); ep->engr_time = e_time; ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE-1); ep->engr_lth = strlen(s) + 1; @@ -530,7 +530,11 @@ return(0); } if (IS_GRAVE(levl[u.ux][u.uy].typ)) { - if (!levl[u.ux][u.uy].disturbed) { + if (otmp == &zeroobj) { /* using only finger */ + You("would only make a small smudge on the %s.", + surface(u.ux, u.uy)); + return(0); + } else if (!levl[u.ux][u.uy].disturbed) { You("disturb the undead!"); levl[u.ux][u.uy].disturbed = 1; (void) makemon(&mons[PM_GHOUL], u.ux, u.uy, NO_MM_FLAGS); @@ -546,7 +550,7 @@ case AMULET_CLASS: case CHAIN_CLASS: case POTION_CLASS: - case GOLD_CLASS: + case COIN_CLASS: break; case RING_CLASS: @@ -706,6 +710,8 @@ } if (!Blind) Strcpy(post_engr_text, + IS_GRAVE(levl[u.ux][u.uy].typ) ? + "Chips fly out from the headstone." : is_ice(u.ux,u.uy) ? "Ice chips fly up from the ice surface!" : "Gravel flies up from the floor."); @@ -931,6 +937,10 @@ "write in"); eloc = is_ice(u.ux,u.uy) ? "frost" : "dust"; break; + case HEADSTONE: + everb = (oep && !eow ? "add to the epitaph on" : + "engrave on"); + break; case ENGRAVE: everb = (oep && !eow ? "add to the engraving in" : "engrave in"); @@ -1011,6 +1021,7 @@ multi = -(len/10); if (multi) nomovemsg = "You finish writing in the dust."; break; + case HEADSTONE: case ENGRAVE: multi = -(len/10); if ((otmp->oclass == WEAPON_CLASS) && @@ -1181,7 +1192,7 @@ tx = rn1(COLNO-3,2); ty = rn2(ROWNO); } while (engr_at(tx, ty) || - !goodpos(tx, ty, (struct monst *)0)); + !goodpos(tx, ty, (struct monst *)0, 0)); ep->engr_x = tx; ep->engr_y = ty; diff -Naurd ../nethack-3.4.0/src/exper.c ./src/exper.c --- ../nethack-3.4.0/src/exper.c Wed Mar 20 23:43:05 2002 +++ ./src/exper.c Mon Feb 24 15:25:05 2003 @@ -49,10 +49,11 @@ tmp = 1 + mtmp->m_lev * mtmp->m_lev; /* For higher ac values, give extra experience */ - if((i = find_mac(mtmp)) < 3) tmp += (7 - i) * (i < 0) ? 2 : 1; + if ((i = find_mac(mtmp)) < 3) tmp += (7 - i) * ((i < 0) ? 2 : 1); /* For very fast monsters, give extra experience */ - if(ptr->mmove >= 12) tmp += (ptr->mmove >= 18) ? 5 : 3; + if (ptr->mmove > NORMAL_SPEED) + tmp += (ptr->mmove > (3*NORMAL_SPEED/2)) ? 5 : 3; /* For each "special" attack type give extra experience */ for(i = 0; i < NATTK; i++) { @@ -115,7 +116,14 @@ { register int num; - if (resists_drli(&youmonst)) return; +#ifdef WIZARD + /* override life-drain resistance when handling an explicit + wizard mode request to reduce level; never fatal though */ + if (drainer && !strcmp(drainer, "#levelchange")) + drainer = 0; + else +#endif + if (resists_drli(&youmonst)) return; if (u.ulevel > 1) { pline("%s level %d.", Goodbye(), u.ulevel--); @@ -140,10 +148,10 @@ if (u.ulevel < urole.xlev) num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd, - urole.enadv.lofix + urace.enadv.lofix); + urole.enadv.lofix + urace.enadv.lofix); else num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd, - urole.enadv.hifix + urace.enadv.hifix); + urole.enadv.hifix + urace.enadv.hifix); num = enermod(num); /* M. Stephenson */ u.uenmax -= num; if (u.uenmax < 0) u.uenmax = 0; @@ -209,17 +217,32 @@ flags.botl = 1; } +/* compute a random amount of experience points suitable for the hero's + experience level: base number of points needed to reach the current + level plus a random portion of what it takes to get to the next level */ long -rndexp() +rndexp(gaining) +boolean gaining; /* gaining XP via potion vs setting XP for polyself */ { - long minexp, maxexp, diff, factor; + long minexp, maxexp, diff, factor, result; minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1); maxexp = newuexp(u.ulevel); diff = maxexp - minexp, factor = 1L; + /* make sure that `diff' is an argument which rn2() can handle */ while (diff >= (long)LARGEST_INT) diff /= 2L, factor *= 2L; - return minexp + factor * (long)rn2((int)diff); + result = minexp + factor * (long)rn2((int)diff); + /* 3.4.1: if already at level 30, add to current experience + points rather than to threshold needed to reach the current + level; otherwise blessed potions of gain level can result + in lowering the experience points instead of raising them */ + if (u.ulevel == MAXULEV && gaining) { + result += (u.uexp - minexp); + /* avoid wrapping (over 400 blessed potions needed for that...) */ + if (result < u.uexp) result = u.uexp; + } + return result; } /*exper.c*/ diff -Naurd ../nethack-3.4.0/src/explode.c ./src/explode.c --- ../nethack-3.4.0/src/explode.c Wed Mar 20 23:43:05 2002 +++ ./src/explode.c Mon Feb 24 15:25:05 2003 @@ -188,7 +188,7 @@ } curs_on_u(); /* will flush screen and output */ - if (any_shield) { /* simulate a shield effect */ + if (any_shield && flags.sparkle) { /* simulate shield effect */ for (k = 0; k < SHIELD_COUNT; k++) { for (i=0; i<3; i++) for (j=0; j<3; j++) { if (explmask[i][j] == 1) @@ -264,8 +264,10 @@ (adtyp == AD_DRST) ? "intoxicated" : (adtyp == AD_ACID) ? "burned" : "fried"); - } else if (cansee(i+x-1, j+y-1)) + } else if (cansee(i+x-1, j+y-1)) { + if(mtmp->m_ap_type) seemimic(mtmp); pline("%s is caught in the %s!", Monnam(mtmp), str); + } idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp); idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp); @@ -314,7 +316,8 @@ if (Invulnerable) { damu = 0; You("are unharmed!"); - } + } else if (Half_physical_damage && adtyp == AD_PHYS) + damu = (damu+1) / 2; if (adtyp == AD_FIRE) (void) burnarmor(&youmonst); destroy_item(SCROLL_CLASS, (int) adtyp); destroy_item(SPBOOK_CLASS, (int) adtyp); @@ -344,6 +347,10 @@ killer_format = NO_KILLER_PREFIX; Sprintf(killer_buf, "caught %sself in %s own %s", uhim(), uhis(), str); + } else if (!strncmpi(str,"tower of flame", 8) || + !strncmpi(str,"fireball", 8)) { + killer_format = KILLED_BY_AN; + Strcpy(killer_buf, str); } else { killer_format = KILLED_BY; Strcpy(killer_buf, str); @@ -360,7 +367,8 @@ if (shopdamage) { pay_for_damage(adtyp == AD_FIRE ? "burn away" : adtyp == AD_COLD ? "shatter" : - adtyp == AD_DISN ? "disintegrate" : "destroy"); + adtyp == AD_DISN ? "disintegrate" : "destroy", + FALSE); } /* explosions are noisy */ @@ -392,7 +400,8 @@ * MAY_FRACTURE Stone objects can be fractured (statues, boulders) */ -void +/* returns number of scattered objects */ +long scatter(sx,sy,blastforce,scflags, obj) int sx,sy; /* location of objects to scatter */ int blastforce; /* force behind the scattering */ @@ -405,11 +414,11 @@ uchar typ; long qtmp; boolean used_up; - boolean split_up = FALSE; boolean individual_object = obj ? TRUE : FALSE; struct monst *mtmp; struct scatter_chain *stmp, *stmp2 = 0; struct scatter_chain *schain = (struct scatter_chain *)0; + long total = 0L; while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) { if (otmp->quan > 1L) { @@ -417,17 +426,8 @@ if (qtmp > LARGEST_INT) qtmp = LARGEST_INT; qtmp = (long)rnd((int)qtmp); otmp = splitobj(otmp, qtmp); - if (rn2(qtmp)) - split_up = TRUE; - else - split_up = FALSE; - } else - split_up = FALSE; - if (individual_object) { - if (split_up) { - obj = otmp; - } else - obj = (struct obj *)0; + } else { + obj = (struct obj *)0; /* all used */ } obj_extract_self(otmp); used_up = FALSE; @@ -439,7 +439,7 @@ if (otmp->otyp == BOULDER) { pline("%s apart.", Tobjnam(otmp, "break")); fracture_rock(otmp); - place_object(otmp, sx, sy); /* put fragments on floor */ + place_object(otmp, sx, sy); if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) { /* another boulder here, restack it to the top */ obj_extract_self(otmp); @@ -541,12 +541,16 @@ stmp2 = stmp->next; x = stmp->ox; y = stmp->oy; if (stmp->obj) { + if ( x!=sx || y!=sy ) + total += stmp->obj->quan; place_object(stmp->obj, x, y); stackobj(stmp->obj); } free((genericptr_t)stmp); newsym(x,y); } + + return total; } diff -Naurd ../nethack-3.4.0/src/files.c ./src/files.c --- ../nethack-3.4.0/src/files.c Wed Mar 20 23:43:06 2002 +++ ./src/files.c Mon Feb 24 15:25:05 2003 @@ -14,11 +14,25 @@ #if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C) #include #endif -#if defined(UNIX) || defined(VMS) + #include -# ifndef SKIP_ERRNO -extern int errno; +#ifdef _MSC_VER /* MSC 6.0 defines errno quite differently */ +# if (_MSC_VER >= 600) +# define SKIP_ERRNO +# endif +#endif +#ifndef SKIP_ERRNO +# ifdef _DCC +const # endif +extern int errno; +#endif + +#if defined(UNIX) && defined(QT_GRAPHICS) +#include +#endif + +#if defined(UNIX) || defined(VMS) #include #endif @@ -34,7 +48,7 @@ #endif #ifdef PREFIXES_IN_USE -#define FQN_NUMBUF 2 +#define FQN_NUMBUF 4 static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME]; #endif @@ -75,6 +89,17 @@ char SAVEP[SAVESIZE]; /* holds path of directory for save file */ #endif +#ifdef HOLD_LOCKFILE_OPEN +struct level_ftrack { +int fd; /* file descriptor for level file */ +int oflag; /* open flags */ +boolean nethack_thinks_it_is_open; /* Does NetHack think it's open? */ +} lftrack; +# if defined(WIN32) +#include +# endif +#endif /*HOLD_LOCKFILE_OPEN*/ + #ifdef WIZARD #define WIZKIT_MAX 128 static char wizkit[WIZKIT_MAX]; @@ -99,8 +124,10 @@ #define Delay(a) msleep(a) # endif #define Close close +#ifndef WIN_CE #define DeleteFile unlink #endif +#endif #ifdef USER_SOUNDS extern char *sounddir; @@ -116,11 +143,123 @@ #endif STATIC_DCL char *FDECL(make_lockname, (const char *,char *)); STATIC_DCL FILE *FDECL(fopen_config_file, (const char *)); -STATIC_DCL int FDECL(get_uchars, (FILE *,char *,char *,uchar *,int,const char *)); +STATIC_DCL int FDECL(get_uchars, (FILE *,char *,char *,uchar *,BOOLEAN_P,int,const char *)); int FDECL(parse_config_line, (FILE *,char *,char *,char *)); #ifdef NOCWD_ASSUMPTIONS STATIC_DCL void FDECL(adjust_prefix, (char *, int)); #endif +#ifdef SELF_RECOVER +STATIC_DCL boolean FDECL(copy_bytes, (int, int)); +#endif +#ifdef HOLD_LOCKFILE_OPEN +STATIC_DCL int FDECL(open_levelfile_exclusively, (const char *, int, int)); +#endif + +/* + * fname_encode() + * + * Args: + * legal zero-terminated list of acceptable file name characters + * quotechar lead-in character used to quote illegal characters as hex digits + * s string to encode + * callerbuf buffer to house result + * bufsz size of callerbuf + * + * Notes: + * The hex digits 0-9 and A-F are always part of the legal set due to + * their use in the encoding scheme, even if not explicitly included in 'legal'. + * + * Sample: + * The following call: + * (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", + * '%', "This is a % test!", buf, 512); + * results in this encoding: + * "This%20is%20a%20%25%20test%21" + */ +char * +fname_encode(legal, quotechar, s, callerbuf, bufsz) +const char *legal; +char quotechar; +char *s, *callerbuf; +int bufsz; +{ + char *sp, *op; + int cnt = 0; + static char hexdigits[] = "0123456789ABCDEF"; + + sp = s; + op = callerbuf; + *op = '\0'; + + while (*sp) { + /* Do we have room for one more character or encoding? */ + if ((bufsz - cnt) <= 4) return callerbuf; + + if (*sp == quotechar) { + (void)sprintf(op, "%c%02X", quotechar, *sp); + op += 3; + cnt += 3; + } else if ((index(legal, *sp) != 0) || (index(hexdigits, *sp) != 0)) { + *op++ = *sp; + *op = '\0'; + cnt++; + } else { + (void)sprintf(op,"%c%02X", quotechar, *sp); + op += 3; + cnt += 3; + } + sp++; + } + return callerbuf; +} + +/* + * fname_decode() + * + * Args: + * quotechar lead-in character used to quote illegal characters as hex digits + * s string to decode + * callerbuf buffer to house result + * bufsz size of callerbuf + */ +char * +fname_decode(quotechar, s, callerbuf, bufsz) +char quotechar; +char *s, *callerbuf; +int bufsz; +{ + char *sp, *op; + int k,calc,cnt = 0; + static char hexdigits[] = "0123456789ABCDEF"; + + sp = s; + op = callerbuf; + *op = '\0'; + calc = 0; + + while (*sp) { + /* Do we have room for one more character? */ + if ((bufsz - cnt) <= 2) return callerbuf; + if (*sp == quotechar) { + sp++; + for (k=0; k < 16; ++k) if (*sp == hexdigits[k]) break; + if (k >= 16) return callerbuf; /* impossible, so bail */ + calc = k << 4; + sp++; + for (k=0; k < 16; ++k) if (*sp == hexdigits[k]) break; + if (k >= 16) return callerbuf; /* impossible, so bail */ + calc += k; + sp++; + *op++ = calc; + *op = '\0'; + } else { + *op++ = *sp++; + *op = '\0'; + } + cnt++; + } + return callerbuf; +} #ifndef PREFIXES_IN_USE /*ARGSUSED*/ @@ -153,18 +292,60 @@ #endif } +/* reasonbuf must be at least BUFSZ, supplied by caller */ +/*ARGSUSED*/ +int +validate_prefix_locations(reasonbuf) +char *reasonbuf; +{ +#if defined(NOCWD_ASSUMPTIONS) + FILE *fp; + const char *filename; + int prefcnt, failcount = 0; + char panicbuf1[BUFSZ], panicbuf2[BUFSZ], *details; + + if (reasonbuf) reasonbuf[0] = '\0'; + for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) { + /* don't test writing to configdir or datadir; they're readonly */ + if (prefcnt == CONFIGPREFIX || prefcnt == DATAPREFIX) continue; + filename = fqname("validate", prefcnt, 3); + if ((fp = fopen(filename, "w"))) { + fclose(fp); + (void) unlink(filename); + } else { + if (reasonbuf) { + if (failcount) Strcat(reasonbuf,", "); + Strcat(reasonbuf, fqn_prefix_names[prefcnt]); + } + /* the paniclog entry gets the value of errno as well */ + Sprintf(panicbuf1,"Invalid %s", fqn_prefix_names[prefcnt]); +#if defined (NHSTDC) && !defined(NOTSTDC) + if (!(details = strerror(errno))) +#endif + details = ""; + Sprintf(panicbuf2,"\"%s\", (%d) %s", + fqn_prefix[prefcnt], errno, details); + paniclog(panicbuf1, panicbuf2); + failcount++; + } + } + if (failcount) + return 0; + else +#endif + return 1; +} /* fopen a file, with OS-dependent bells and whistles */ /* NOTE: a simpler version of this routine also exists in util/dlb_main.c */ FILE * -fopen_datafile(filename, mode, use_scoreprefix) +fopen_datafile(filename, mode, prefix) const char *filename, *mode; -boolean use_scoreprefix; +int prefix; { FILE *fp; - filename = fqname(filename, - use_scoreprefix ? SCOREPREFIX : DATAPREFIX, 0); + filename = fqname(filename, prefix, prefix == TROUBLEPREFIX ? 3 : 0); #ifdef VMS /* essential to have punctuation, to avoid logical names */ { char tmp[BUFSIZ]; @@ -229,19 +410,27 @@ } int -create_levelfile(lev) +create_levelfile(lev, errbuf) int lev; +char errbuf[]; { int fd; const char *fq_lock; + if (errbuf) *errbuf = '\0'; set_levelfile_name(lock, lev); fq_lock = fqname(lock, LEVELPREFIX, 0); -#if defined(MICRO) +#if defined(MICRO) || defined(WIN32) /* Use O_TRUNC to force the file to be shortened if it already * exists and is currently longer. */ +# ifdef HOLD_LOCKFILE_OPEN + if (lev == 0) + fd = open_levelfile_exclusively(fq_lock, lev, + O_WRONLY |O_CREAT | O_TRUNC | O_BINARY); + else +# endif fd = open(fq_lock, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); #else # ifdef MAC @@ -249,22 +438,28 @@ # else fd = creat(fq_lock, FCMASK); # endif -#endif /* MICRO */ +#endif /* MICRO || WIN32 */ if (fd >= 0) level_info[lev].flags |= LFILE_EXISTS; + else if (errbuf) /* failure explanation */ + Sprintf(errbuf, + "Cannot create file \"%s\" for level %d (errno %d).", + lock, lev, errno); return fd; } int -open_levelfile(lev) +open_levelfile(lev, errbuf) int lev; +char errbuf[]; { int fd; const char *fq_lock; + if (errbuf) *errbuf = '\0'; set_levelfile_name(lock, lev); fq_lock = fqname(lock, LEVELPREFIX, 0); #ifdef MFLOPPY @@ -275,8 +470,22 @@ #ifdef MAC fd = macopen(fq_lock, O_RDONLY | O_BINARY, LEVL_TYPE); #else +# ifdef HOLD_LOCKFILE_OPEN + if (lev == 0) + fd = open_levelfile_exclusively(fq_lock, lev, O_RDONLY | O_BINARY ); + else +# endif fd = open(fq_lock, O_RDONLY | O_BINARY, 0); #endif + + /* for failure, return an explanation that our caller can use; + settle for `lock' instead of `fq_lock' because the latter + might end up being too big for nethack's BUFSZ */ + if (fd < 0 && errbuf) + Sprintf(errbuf, + "Cannot open file \"%s\" for level %d (errno %d).", + lock, lev, errno); + return fd; } @@ -291,6 +500,9 @@ */ if (lev == 0 || (level_info[lev].flags & LFILE_EXISTS)) { set_levelfile_name(lock, lev); +#ifdef HOLD_LOCKFILE_OPEN + if (lev == 0) really_close(); +#endif (void) unlink(fqname(lock, LEVELPREFIX, 0)); level_info[lev].flags &= ~LFILE_EXISTS; } @@ -316,6 +528,62 @@ #endif } +#ifdef HOLD_LOCKFILE_OPEN +STATIC_OVL int +open_levelfile_exclusively(name, lev, oflag) +const char *name; +int lev, oflag; +{ + int reslt, fd; + if (lftrack.fd) { + /* check for compatible access */ + if (lftrack.oflag == oflag) { + fd = lftrack.fd; + reslt = lseek(fd, 0L, SEEK_SET); + if (reslt == -1L) + panic("open_levelfile_exclusively: lseek failed %d", reslt); + lftrack.nethack_thinks_it_is_open = TRUE; + } else { + really_close(); + fd = sopen(name, oflag,SH_DENYRW, FCMASK); + lftrack.fd = fd; + lftrack.oflag = oflag; + lftrack.nethack_thinks_it_is_open = TRUE; + } + } else { + fd = sopen(name, oflag,SH_DENYRW, FCMASK); + lftrack.fd = fd; + lftrack.oflag = oflag; + if (fd) + lftrack.nethack_thinks_it_is_open = TRUE; + } + return fd; +} + +void +really_close() +{ + int fd = lftrack.fd; + lftrack.nethack_thinks_it_is_open = FALSE; + lftrack.fd = 0; + lftrack.oflag = 0; + (void)_close(fd); + return; +} + +close(fd) +int fd; +{ + if (lftrack.fd == fd) { + really_close(); /* close it, but reopen it to hold it */ + fd = open_levelfile(0, (char *)0); + lftrack.nethack_thinks_it_is_open = FALSE; + return 0; + } + return _close(fd); +} +#endif + /* ---------- END LEVEL FILE HANDLING ----------- */ @@ -366,18 +634,20 @@ } int -create_bonesfile(lev, bonesid) +create_bonesfile(lev, bonesid, errbuf) d_level *lev; char **bonesid; +char errbuf[]; { const char *file; int fd; + if (errbuf) *errbuf = '\0'; *bonesid = set_bonesfile_name(bones, lev); file = set_bonestemp_name(); file = fqname(file, BONESPREFIX, 0); -#ifdef MICRO +#if defined(MICRO) || defined(WIN32) /* Use O_TRUNC to force the file to be shortened if it already * exists and is currently longer. */ @@ -388,6 +658,12 @@ # else fd = creat(file, FCMASK); # endif +#endif + if (fd < 0 && errbuf) /* failure explanation */ + Sprintf(errbuf, + "Cannot create bones \"%s\", id %s (errno %d).", + lock, *bonesid, errno); + # if defined(VMS) && !defined(SECURE) /* Re-protect bones file with world:read+write+execute+delete access. @@ -399,7 +675,6 @@ */ (void) chmod(file, FCMASK | 007); /* allow other users full access */ # endif /* VMS && !SECURE */ -#endif /* MICRO */ return fd; } @@ -442,7 +717,7 @@ #endif #ifdef WIZARD if (wizard && ret != 0) - pline("couldn't rename %s to %s", tempname, fq_bones); + pline("couldn't rename %s to %s.", tempname, fq_bones); #endif } @@ -641,6 +924,104 @@ return fd; } +/*ARGSUSED*/ +static char* +plname_from_file(filename) +const char* filename; +{ +#ifdef STORE_PLNAME_IN_FILE + int fd; + char* result = 0; + + Strcpy(SAVEF,filename); +#ifdef COMPRESS_EXTENSION + SAVEF[strlen(SAVEF)-strlen(COMPRESS_EXTENSION)] = '\0'; +#endif + uncompress(SAVEF); + if ((fd = open_savefile()) >= 0) { + if (uptodate(fd, filename)) { + char tplname[PL_NSIZ]; + mread(fd, (genericptr_t) tplname, PL_NSIZ); + result = strdup(tplname); + } + (void) close(fd); + } + compress(SAVEF); + + return result; +#else +# if defined(UNIX) && defined(QT_GRAPHICS) + /* Name not stored in save file, so we have to extract it from + the filename, which loses information + (eg. "/", "_", and "." characters are lost. */ + int k; + int uid; + char name[NAME_MAX]; +#ifdef COMPRESS_EXTENSION +#define EXTSTR COMPRESS_EXTENSION +#else +#define EXTSTR "" +#endif + if ( sscanf( filename, "%*[^/]/%d%[^.]" EXTSTR, &uid, name ) == 2 ) { +#undef EXTSTR + /* "_" most likely means " ", which certainly looks nicer */ + for (k=0; name[k]; k++) + if ( name[k]=='_' ) + name[k]=' '; + return strdup(name); + } else +# endif + { + return 0; + } +#endif +} + +char** +get_saved_games() +{ +#if defined(UNIX) && defined(QT_GRAPHICS) + int myuid=getuid(); + struct dirent **namelist; + int n = scandir("save", &namelist, 0, alphasort);; + if ( n > 0 ) { + int i,j=0; + char** result = (char**)alloc((n+1)*sizeof(char*)); /* at most */ + for (i=0; id_name, "%d%s", &uid, name ) == 2 ) { + if ( uid == myuid ) { + char filename[BUFSZ]; + char* r; + Sprintf(filename,"save/%d%s",uid,name); + r = plname_from_file(filename); + if ( r ) + result[j++] = r; + } + } + } + result[j++] = 0; + return result; + } else +#endif + { + return 0; + } +} + +void +free_saved_games(saved) +char** saved; +{ + if ( saved ) { + int i=0; + while (saved[i]) free((genericptr_t)saved[i++]); + free((genericptr_t)saved); + } +} + + /* ---------- END SAVE FILE HANDLING ----------- */ @@ -909,7 +1290,7 @@ lockname = make_lockname(filename, locknambuf); filename = fqname(filename, whichprefix, 0); #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */ - lockname = fqname(lockname, LOCKPREFIX, 1); + lockname = fqname(lockname, LOCKPREFIX, 2); #endif #if defined(UNIX) || defined(VMS) @@ -1013,7 +1394,7 @@ if (nesting == 1) { lockname = make_lockname(filename, locknambuf); #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */ - lockname = fqname(lockname, LOCKPREFIX, 1); + lockname = fqname(lockname, LOCKPREFIX, 2); #endif #if defined(UNIX) || defined(VMS) @@ -1166,27 +1547,33 @@ /* * Retrieve a list of integers from a file into a uchar array. * - * NOTE: This routine is unable to read a value of 0. + * NOTE: zeros are inserted unless modlist is TRUE, in which case the list + * location is unchanged. Callers must handle zeros if modlist is FALSE. */ STATIC_OVL int -get_uchars(fp, buf, bufp, list, size, name) +get_uchars(fp, buf, bufp, list, modlist, size, name) FILE *fp; /* input file pointer */ char *buf; /* read buffer, must be of size BUFSZ */ char *bufp; /* current pointer */ uchar *list; /* return list */ + boolean modlist; /* TRUE: list is being modified in place */ int size; /* return list size */ const char *name; /* name of option for error message */ { unsigned int num = 0; int count = 0; + boolean havenum = FALSE; while (1) { switch(*bufp) { case ' ': case '\0': case '\t': case '\n': - if (num) { - list[count++] = num; + if (havenum) { + /* if modifying in place, don't insert zeros */ + if (num || !modlist) list[count] = num; + count++; num = 0; + havenum = FALSE; } if (count == size || !*bufp) return count; bufp++; @@ -1195,6 +1582,7 @@ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + havenum = TRUE; num = num*10 + (*bufp-'0'); bufp++; break; @@ -1290,7 +1678,7 @@ } else if (match_varname(buf, "LEVELDIR", 4) || match_varname(buf, "LEVELS", 4)) { adjust_prefix(bufp, LEVELPREFIX); - } else if (match_varname(buf, "SAVE", 4)) { + } else if (match_varname(buf, "SAVEDIR", 4)) { adjust_prefix(bufp, SAVEPREFIX); } else if (match_varname(buf, "BONESDIR", 5)) { adjust_prefix(bufp, BONESPREFIX); @@ -1302,6 +1690,8 @@ adjust_prefix(bufp, LOCKPREFIX); } else if (match_varname(buf, "CONFIGDIR", 4)) { adjust_prefix(bufp, CONFIGPREFIX); + } else if (match_varname(buf, "TROUBLEDIR", 4)) { + adjust_prefix(bufp, TROUBLEPREFIX); #else /*NOCWD_ASSUMPTIONS*/ # ifdef MICRO } else if (match_varname(buf, "HACKDIR", 4)) { @@ -1354,30 +1744,35 @@ (void) strncpy(catname, bufp, PL_PSIZ-1); } else if (match_varname(buf, "BOULDER", 3)) { - (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, 1, "BOULDER"); + (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, TRUE, + 1, "BOULDER"); } else if (match_varname(buf, "GRAPHICS", 4)) { - len = get_uchars(fp, buf, bufp, translate, MAXPCHARS, "GRAPHICS"); + len = get_uchars(fp, buf, bufp, translate, FALSE, + MAXPCHARS, "GRAPHICS"); assign_graphics(translate, len, MAXPCHARS, 0); } else if (match_varname(buf, "DUNGEON", 4)) { - len = get_uchars(fp, buf, bufp, translate, MAXDCHARS, "DUNGEON"); + len = get_uchars(fp, buf, bufp, translate, FALSE, + MAXDCHARS, "DUNGEON"); assign_graphics(translate, len, MAXDCHARS, 0); } else if (match_varname(buf, "TRAPS", 4)) { - len = get_uchars(fp, buf, bufp, translate, MAXTCHARS, "TRAPS"); + len = get_uchars(fp, buf, bufp, translate, FALSE, + MAXTCHARS, "TRAPS"); assign_graphics(translate, len, MAXTCHARS, MAXDCHARS); } else if (match_varname(buf, "EFFECTS", 4)) { - len = get_uchars(fp, buf, bufp, translate, MAXECHARS, "EFFECTS"); + len = get_uchars(fp, buf, bufp, translate, FALSE, + MAXECHARS, "EFFECTS"); assign_graphics(translate, len, MAXECHARS, MAXDCHARS+MAXTCHARS); } else if (match_varname(buf, "OBJECTS", 3)) { /* oc_syms[0] is the RANDOM object, unused */ - (void) get_uchars(fp, buf, bufp, &(oc_syms[1]), + (void) get_uchars(fp, buf, bufp, &(oc_syms[1]), TRUE, MAXOCLASSES-1, "OBJECTS"); } else if (match_varname(buf, "MONSTERS", 3)) { /* monsyms[0] is unused */ - (void) get_uchars(fp, buf, bufp, &(monsyms[1]), + (void) get_uchars(fp, buf, bufp, &(monsyms[1]), TRUE, MAXMCLASSES-1, "MONSTERS"); } else if (match_varname(buf, "WARNINGS", 5)) { - (void) get_uchars(fp, buf, bufp, translate, + (void) get_uchars(fp, buf, bufp, translate, FALSE, WARNCOUNT, "WARNINGS"); assign_warnings(translate); #ifdef WIZARD @@ -1501,6 +1896,7 @@ add_sound_mapping(bufp); #endif #ifdef QT_GRAPHICS + /* These should move to wc_ options */ } else if (match_varname(buf, "QT_TILEWIDTH", 12)) { extern char *qt_tilewidth; if (qt_tilewidth == NULL) @@ -1671,21 +2067,33 @@ FILE *fp; char *ep, buf[BUFSZ]; struct obj *otmp; + boolean bad_items = FALSE, skip = FALSE; + if (!wizard || !(fp = fopen_wizkit_file())) return; - while (fgets(buf, 4*BUFSZ, fp)) { - if ((ep = index(buf, '\n'))) *ep = '\0'; + while (fgets(buf, (int)(sizeof buf), fp)) { + ep = index(buf, '\n'); + if (skip) { /* in case previous line was too long */ + if (ep) skip = FALSE; /* found newline; next line is normal */ + } else { + if (!ep) skip = TRUE; /* newline missing; discard next fgets */ + else *ep = '\0'; /* remove newline */ + if (buf[0]) { otmp = readobjnam(buf, (struct obj *)0, FALSE); if (otmp) { if (otmp != &zeroobj) otmp = addinv(otmp); } else { - raw_printf("Bad wizkit item: \"%.50s\"", buf); - wait_synch(); + /* .60 limits output line width to 79 chars */ + raw_printf("Bad wizkit item: \"%.60s\"", buf); + bad_items = TRUE; } } + } } + if (bad_items) + wait_synch(); (void) fclose(fp); return; } diff -Naurd ../nethack-3.4.0/src/fountain.c ./src/fountain.c --- ../nethack-3.4.0/src/fountain.c Wed Mar 20 23:43:06 2002 +++ ./src/fountain.c Mon Feb 24 15:25:05 2003 @@ -43,9 +43,9 @@ void dowaterdemon() /* Water demon */ { - register struct monst *mtmp; + register struct monst *mtmp; - if(mvitals[PM_WATER_DEMON].mvflags & G_GONE) return; + if(!(mvitals[PM_WATER_DEMON].mvflags & G_GONE)) { if((mtmp = makemon(&mons[PM_WATER_DEMON],u.ux,u.uy, NO_MM_FLAGS))) { if (!Blind) You("unleash %s!", a_monnam(mtmp)); @@ -61,6 +61,8 @@ } else if (t_at(mtmp->mx, mtmp->my)) (void) mintrap(mtmp); } + } else + pline_The("fountain bubbles furiously for a moment, then calms."); } STATIC_OVL void @@ -68,8 +70,8 @@ { register struct monst *mtmp; - if(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) return; - if((mtmp = makemon(&mons[PM_WATER_NYMPH],u.ux,u.uy, NO_MM_FLAGS))) { + if(!(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) && + (mtmp = makemon(&mons[PM_WATER_NYMPH],u.ux,u.uy, NO_MM_FLAGS))) { if (!Blind) You("attract %s!", a_monnam(mtmp)); else @@ -138,7 +140,7 @@ else You_feel("a gem here!"); (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE-1), u.ux, u.uy, FALSE, FALSE); - levl[u.ux][u.uy].looted |= F_LOOTED; + SET_FOUNTAIN_LOOTED(u.ux,u.uy); newsym(u.ux, u.uy); exercise(A_WIS, TRUE); /* a discovery! */ } @@ -149,12 +151,10 @@ boolean isyou; { if (IS_FOUNTAIN(levl[x][y].typ) && - (!rn2(3) || (levl[x][y].looted & F_WARNED))) { - s_level *slev = Is_special(&u.uz); - if(isyou && slev && slev->flags.town && - !(levl[x][y].looted & F_WARNED)) { + (!rn2(3) || FOUNTAIN_IS_WARNED(x,y))) { + if(isyou && in_town(x, y) && !FOUNTAIN_IS_WARNED(x,y)) { struct monst *mtmp; - levl[x][y].looted |= F_WARNED; + SET_FOUNTAIN_WARNED(x,y); /* Warn about future fountain use. */ for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; @@ -177,15 +177,16 @@ return; } #endif - if (cansee(x,y)) pline_The("fountain dries up!"); + /* replace the fountain with ordinary floor */ levl[x][y].typ = ROOM; levl[x][y].looted = 0; levl[x][y].blessedftn = 0; + if (cansee(x,y)) pline_The("fountain dries up!"); /* The location is seen if the hero/monster is invisible */ /* or felt if the hero is blind. */ newsym(x, y); level.flags.nfountains--; - if(isyou && slev && slev->flags.town) + if(isyou && in_town(x, y)) (void) angry_guards(FALSE); } } @@ -254,7 +255,9 @@ pline_The("water is contaminated!"); if (Poison_resistance) { - pline("Perhaps it is runoff from the nearby %s farm.", pl_fruit); + pline( + "Perhaps it is runoff from the nearby %s farm.", + fruitname(FALSE)); losehp(rnd(4),"unrefrigerated sip of juice", KILLED_BY_AN); break; @@ -287,12 +290,12 @@ case 25: /* See invisible */ if (Blind) { - if (Invisible) { - You("feel very self-conscious."); - pline("Then it passes."); - } else { - You("feel transparent."); - } + if (Invisible) { + You("feel transparent."); + } else { + You("feel very self-conscious."); + pline("Then it passes."); + } } else { You("see an image of someone stalking you."); pline("But it disappears."); @@ -310,7 +313,7 @@ case 27: /* Find a gem in the sparkling waters. */ - if (!levl[u.ux][u.uy].looted) { + if (!FOUNTAIN_IS_LOOTED(u.ux,u.uy)) { dofindgem(); break; } @@ -359,7 +362,6 @@ && u.ulevel >= 5 && !rn2(6) && !obj->oartifact && !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) { - s_level *slev = Is_special(&u.uz); if (u.ualign.type != A_LAWFUL) { /* Ha! Trying to cheat her. */ @@ -386,7 +388,7 @@ levl[u.ux][u.uy].looted = 0; if(Invisible) newsym(u.ux, u.uy); level.flags.nfountains--; - if(slev && slev->flags.town) + if(in_town(u.ux, u.uy)) (void) angry_guards(FALSE); return; } else (void) get_wet(obj); @@ -423,7 +425,7 @@ dowatersnakes(); break; case 24: /* Find a gem */ - if (!levl[u.ux][u.uy].looted) { + if (!FOUNTAIN_IS_LOOTED(u.ux,u.uy)) { dofindgem(); break; } @@ -443,7 +445,7 @@ if (u.ugold > 10) { u.ugold -= somegold() / 10; You("lost some of your gold in the fountain!"); - levl[u.ux][u.uy].looted &= ~F_LOOTED; + CLEAR_FOUNTAIN_LOOTED(u.ux,u.uy); exercise(A_WIS, FALSE); } #else @@ -453,7 +455,7 @@ if (money > 10) { /* Amount to loose. Might get rounded up as fountains don't pay change... */ money = somegold(money) / 10; - for (otmp = invent; otmp && money > 0; otmp = otmp->nobj) if (otmp->oclass == GOLD_CLASS) { + for (otmp = invent; otmp && money > 0; otmp = otmp->nobj) if (otmp->oclass == COIN_CLASS) { int denomination = objects[otmp->otyp].oc_cost; long coin_loss = (money + denomination - 1) / denomination; coin_loss = min(coin_loss, otmp->quan); @@ -462,7 +464,7 @@ if (!otmp->quan) delobj(otmp); } You("lost some of your money in the fountain!"); - levl[u.ux][u.uy].looted &= ~F_LOOTED; + CLEAR_FOUNTAIN_LOOTED(u.ux,u.uy); exercise(A_WIS, FALSE); } } @@ -474,8 +476,8 @@ * surface. After all, there will have been more people going * by. Just like a shopping mall! Chris Woodbury */ - if (levl[u.ux][u.uy].looted) break; - levl[u.ux][u.uy].looted |= F_LOOTED; + if (FOUNTAIN_IS_LOOTED(u.ux,u.uy)) break; + SET_FOUNTAIN_LOOTED(u.ux,u.uy); (void) mkgold((long) (rnd((dunlevs_in_dungeon(&u.uz)-dunlev(&u.uz)+1)*2)+5), u.ux, u.uy); diff -Naurd ../nethack-3.4.0/src/hack.c ./src/hack.c --- ../nethack-3.4.0/src/hack.c Wed Mar 20 23:43:06 2002 +++ ./src/hack.c Mon Feb 24 15:25:05 2003 @@ -12,7 +12,7 @@ #ifdef SINKS STATIC_DCL void NDECL(dosinkfall); #endif -STATIC_DCL void NDECL(findtravelpath); +STATIC_DCL boolean FDECL(findtravelpath, (BOOLEAN_P)); STATIC_DCL boolean FDECL(monstinroom, (struct permonst *,int)); STATIC_DCL void FDECL(move_update, (BOOLEAN_P)); @@ -47,7 +47,7 @@ /* this location might not be safe, if not, move revived monster */ if (revived) { mtmp = m_at(x,y); - if (mtmp && !goodpos(x, y, mtmp) && + if (mtmp && !goodpos(x, y, mtmp, 0) && enexto(&cc, x, y, mtmp->data)) { rloc_to(mtmp, cc.x, cc.y); } @@ -89,6 +89,7 @@ goto cannot_push; } if (isok(rx,ry) && !IS_ROCK(levl[rx][ry].typ) && + levl[rx][ry].typ != IRONBARS && (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || ( #ifdef REINCARNATION !Is_rogue_level(&u.uz) && @@ -113,17 +114,17 @@ (!mtmp->mtrapped || !(ttmp && ((ttmp->ttyp == PIT) || (ttmp->ttyp == SPIKED_PIT))))) { + if (Blind) feel_location(sx, sy); if (canspotmon(mtmp)) - pline("There's %s on the other side.", mon_nam(mtmp)); + pline("There's %s on the other side.", a_monnam(mtmp)); else { - if (Blind) feel_location(sx, sy); You_hear("a monster behind %s.", the(xname(otmp))); map_invisible(rx, ry); } if (flags.verbose) pline("Perhaps that's why %s cannot move it.", #ifdef STEED - u.usteed ? mon_nam(u.usteed) : + u.usteed ? y_monnam(u.usteed) : #endif "you"); goto cannot_push; @@ -180,7 +181,7 @@ #ifdef STEED if (u.usteed) pline("%s pushes %s and suddenly it disappears!", - Monnam(u.usteed), the(xname(otmp))); + upstart(y_monnam(u.usteed)), the(xname(otmp))); else #endif You("push %s and suddenly it disappears!", @@ -221,10 +222,9 @@ long lastmovetime; lastmovetime = 0; #else + /* note: reset to zero after save/restore cycle */ static NEARDATA long lastmovetime; #endif - /* note: this var contains garbage initially and - after a restore */ #ifdef STEED if (!u.usteed) { #endif @@ -235,7 +235,8 @@ exercise(A_STR, TRUE); #ifdef STEED } else - pline("%s moves %s.", Monnam(u.usteed), the(xname(otmp))); + pline("%s moves %s.", + upstart(y_monnam(u.usteed)), the(xname(otmp))); #endif lastmovetime = moves; } @@ -255,7 +256,7 @@ #ifdef STEED if (u.usteed) pline("%s tries to move %s, but cannot.", - Monnam(u.usteed), the(xname(otmp))); + upstart(y_monnam(u.usteed)), the(xname(otmp))); else #endif You("try to move %s, but in vain.", the(xname(otmp))); @@ -267,7 +268,7 @@ You("aren't skilled enough to %s %s from %s.", (flags.pickup && !In_sokoban(&u.uz)) ? "pick up" : "push aside", - the(xname(otmp)), mon_nam(u.usteed)); + the(xname(otmp)), y_monnam(u.usteed)); } else #endif { @@ -381,12 +382,15 @@ digtxt = "chew a hole in the wall."; if (level.flags.is_maze_lev) { lev->typ = ROOM; - } else if (level.flags.is_cavernous_lev) { + } else if (level.flags.is_cavernous_lev && !in_town(x, y)) { lev->typ = CORR; } else { lev->typ = DOOR; lev->doormask = D_NODOOR; } + } else if (IS_TREE(lev->typ)) { + digtxt = "chew through the tree."; + lev->typ = ROOM; } else if (lev->typ == SDOOR) { if (lev->doormask & D_TRAPPED) { lev->doormask = D_NODOOR; @@ -418,7 +422,7 @@ unblock_point(x, y); /* vision */ newsym(x, y); if (digtxt) You(digtxt); /* after newsym */ - if (dmgtxt) pay_for_damage(dmgtxt); + if (dmgtxt) pay_for_damage(dmgtxt, FALSE); (void) memset((genericptr_t)&digging, 0, sizeof digging); return 0; } @@ -449,6 +453,13 @@ if (is_floater(youmonst.data) || (HLevitation & FROMOUTSIDE)) { You("wobble unsteadily for a moment."); } else { + long save_ELev = ELevitation, save_HLev = HLevitation; + + /* fake removal of levitation in advance so that final + disclosure will be right in case this turns out to + be fatal; fortunately the fact that rings and boots + are really still worn has no effect on bones data */ + ELevitation = HLevitation = 0L; You("crash to the floor!"); losehp(rn1(8, 25 - (int)ACURR(A_CON)), fell_on_sink, NO_KILLER_PREFIX); @@ -460,6 +471,8 @@ losehp(rnd(3), fell_on_sink, NO_KILLER_PREFIX); exercise(A_CON, FALSE); } + ELevitation = save_ELev; + HLevitation = save_HLev; } ELevitation &= ~W_ARTI; @@ -525,11 +538,13 @@ #endif /* OVL1 */ #ifdef OVL3 -/* return TRUE if (dx,dy) is an OK place to move */ +/* return TRUE if (dx,dy) is an OK place to move + * mode is one of DO_MOVE, TEST_MOVE or TEST_TRAV + */ boolean -test_move(ux, uy, dx, dy, test_only) +test_move(ux, uy, dx, dy, mode) int ux, uy, dx, dy; -boolean test_only; +int mode; { int x = ux+dx; int y = uy+dy; @@ -540,93 +555,101 @@ * Check for physical obstacles. First, the place we are going. */ if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) { - if (Blind && !test_only) feel_location(x,y); + if (Blind && mode == DO_MOVE) feel_location(x,y); if (Passes_walls && may_passwall(x,y)) { ; /* do nothing */ + } else if (tmpr->typ == IRONBARS) { + if (!(Passes_walls || passes_bars(youmonst.data))) + return FALSE; } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) { /* Eat the rock. */ - if (!test_only && still_chewing(x,y)) return FALSE; + if (mode == DO_MOVE && still_chewing(x,y)) return FALSE; } else if (flags.autodig && !flags.run && !flags.nopick && uwep && is_pick(uwep)) { /* MRKR: Automatic digging when wielding the appropriate tool */ - if (!test_only) + if (mode == DO_MOVE) (void) use_pick_axe2(uwep); return FALSE; } else { - if ( !test_only ) { + if (mode == DO_MOVE) { if (Is_stronghold(&u.uz) && is_db_wall(x,y)) pline_The("drawbridge is up!"); if (Passes_walls && !may_passwall(x,y) && In_sokoban(&u.uz)) - pline_The("Sokoban walls resist your ability."); + pline_The("Sokoban walls resist your ability."); } return FALSE; } } else if (IS_DOOR(tmpr->typ)) { if (closed_door(x,y)) { - if (Blind && !test_only) feel_location(x,y); + if (Blind && mode == DO_MOVE) feel_location(x,y); if (Passes_walls) ; /* do nothing */ else if (can_ooze(&youmonst)) { - if ( !test_only ) You("ooze under the door."); + if (mode == DO_MOVE) You("ooze under the door."); } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) { /* Eat the door. */ - if (!test_only && still_chewing(x,y)) return FALSE; + if (mode == DO_MOVE && still_chewing(x,y)) return FALSE; } else { - if ( !test_only ) { + if (mode == DO_MOVE) { if (amorphous(youmonst.data)) You("try to ooze under the door, but can't squeeze your possessions through."); else if (x == ux || y == uy) { if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) { #ifdef STEED - if (u.usteed) + if (u.usteed) { You_cant("lead %s through that closed door.", - x_monnam(u.usteed, - u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - (char *)0, SUPPRESS_SADDLE, FALSE)); - else { -#else + y_monnam(u.usteed)); + } else +#endif + { pline("Ouch! You bump into a door."); exercise(A_DEX, FALSE); -#endif -#ifdef STEED } -#endif } else pline("That door is closed."); } - } + } else if (mode == TEST_TRAV) goto testdiag; return FALSE; } - } else if (dx && dy && !Passes_walls - && ((tmpr->doormask & ~D_BROKEN) + } else { + testdiag: + if (dx && dy && !Passes_walls + && ((tmpr->doormask & ~D_BROKEN) #ifdef REINCARNATION - || Is_rogue_level(&u.uz) + || Is_rogue_level(&u.uz) #endif - || block_door(x,y))) { - /* Diagonal moves into a door are not allowed. */ - if ( Blind && !test_only ) - feel_location(x,y); - return FALSE; + || block_door(x,y))) { + /* Diagonal moves into a door are not allowed. */ + if (Blind && mode == DO_MOVE) + feel_location(x,y); + return FALSE; + } } } if (dx && dy && bad_rock(youmonst.data,ux,y) && bad_rock(youmonst.data,x,uy)) { /* Move at a diagonal. */ if (In_sokoban(&u.uz)) { - if ( !test_only ) + if (mode == DO_MOVE) You("cannot pass that way."); return FALSE; } if (bigmonst(youmonst.data)) { - if ( !test_only ) + if (mode == DO_MOVE) Your("body is too large to fit through."); return FALSE; } if (invent && (inv_weight() + weight_cap() > 600)) { - if ( !test_only ) + if (mode == DO_MOVE) You("are carrying too much to get through."); return FALSE; } } + /* pick a path that does not require crossing a trap */ + if (flags.run == 8 && mode != DO_MOVE) { + struct trap* t = t_at(x, y); + + if (t && t->tseen) return FALSE; + } ust = &levl[ux][uy]; @@ -643,80 +666,164 @@ } if (sobj_at(BOULDER,x,y) && (In_sokoban(&u.uz) || !Passes_walls)) { - if (!(Blind || Hallucination) && (flags.run >= 2)) + if (!(Blind || Hallucination) && (flags.run >= 2) && mode != TEST_TRAV) return FALSE; - if (!test_only) { + if (mode == DO_MOVE) { /* tunneling monsters will chew before pushing */ if (tunnels(youmonst.data) && !needspick(youmonst.data) && !In_sokoban(&u.uz)) { if (still_chewing(x,y)) return FALSE; } else if (moverock() < 0) return FALSE; + } else if (mode == TEST_TRAV) { + struct obj* obj; + + /* don't pick two boulders in a row, unless there's a way thru */ + if (sobj_at(BOULDER,ux,uy) && !In_sokoban(&u.uz)) { + if (!Passes_walls && + !(tunnels(youmonst.data) && !needspick(youmonst.data)) && + !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK) && + !((obj = carrying(WAN_DIGGING)) && + !objects[obj->otyp].oc_name_known)) + return FALSE; + } } - /* test_only will assume you'll be able to push it when you get there... */ + /* assume you'll be able to push it when you get there... */ } /* OK, it is a legal place to move. */ return TRUE; } -static void findtravelpath() +/* + * Find a path from the destination (u.tx,u.ty) back to (u.ux,u.uy). + * A shortest path is returned. If guess is TRUE, consider various + * inaccessible locations as valid intermediate path points. + * Returns TRUE if a path was found. + */ +static boolean +findtravelpath(guess) +boolean guess; { - if ( u.tx != u.ux || u.ty != u.uy ) { + if (u.tx != u.ux || u.ty != u.uy) { xchar travel[COLNO][ROWNO]; xchar travelstepx[2][COLNO*ROWNO]; xchar travelstepy[2][COLNO*ROWNO]; - int n=1; - int set=0; - int dia=1; + xchar tx, ty, ux, uy; + int n = 1; /* max offset in travelsteps */ + int set = 0; /* two sets current and previous */ + int radius = 1; /* search radius */ + int i; - (void) memset((genericptr_t)travel,0,sizeof(travel)); + /* If guessing, first find an "obvious" goal location. The obvious + * goal is the position the player knows of, or might figure out + * (couldsee) that is closest to the target on a straight path. + */ + if (guess) { + tx = u.ux; ty = u.uy; ux = u.tx; uy = u.ty; + } else { + tx = u.tx; ty = u.ty; ux = u.ux; uy = u.uy; + } - travelstepx[0][0] = u.tx; - travelstepy[0][0] = u.ty; - while ( n ) { - int i; - int nn=0; - for (i=0; i %d,%d by %d,%d\n",u.ux,u.uy,u.tx,u.ty,u.dx,u.dy); - */ - return; - } else { - /*printf("%d %d %d",isok(nx,ny), !travel[nx][ny], ACCESSIBLE(levl[nx][ny].typ));*/ - if ( !travel[nx][ny] ) { - travelstepx[1-set][nn]=nx; - travelstepy[1-set][nn]=ny; - travel[nx][ny]=dia; - nn++; + + if (!isok(nx, ny)) continue; + if ((!Passes_walls && !can_ooze(&youmonst) && + closed_door(x, y)) || sobj_at(BOULDER, x, y)) { + /* closed doors and boulders usually + * cause a delay, so prefer another path */ + if (travel[x][y] > radius-3) { + travelstepx[1-set][nn] = x; + travelstepy[1-set][nn] = y; + /* don't change travel matrix! */ + nn++; + continue; + } + } + if (test_move(x, y, nx-x, ny-y, TEST_TRAV) && + (levl[nx][ny].seenv || (!Blind && couldsee(nx, ny)))) { + if (nx == ux && ny == uy) { + if (!guess) { + u.dx = x-ux; + u.dy = y-uy; + if (x == u.tx && y == u.ty) { + nomul(0); + /* reset run so domove run checks work */ + flags.run = 8; + } + return TRUE; } + } else if (!travel[nx][ny]) { + travelstepx[1-set][nn] = nx; + travelstepy[1-set][nn] = ny; + travel[nx][ny] = radius; + nn++; } } } } + n = nn; set = 1-set; - dia++; + radius++; } - /* give up */ + /* if guessing, find best location in travel matrix and go there */ + if (guess) { + int px = tx, py = ty; /* pick location */ + int dist, nxtdist; + + dist = distmin(ux, uy, tx, ty); + for (tx = 1; tx < COLNO; ++tx) + for (ty = 0; ty < ROWNO; ++ty) + if (travel[tx][ty]) { + nxtdist = distmin(ux, uy, tx, ty); + if (nxtdist < dist && couldsee(tx, ty)) { + px = tx; py = ty; dist = nxtdist; + } + } + + if (px == u.ux && py == u.uy) { + /* no guesses, just go in the general direction */ + u.dx = sgn(u.tx - u.ux); + u.dy = sgn(u.ty - u.uy); + if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE)) + return TRUE; + goto found; + } + tx = px; + ty = py; + ux = u.ux; + uy = u.uy; + set = 0; + n = radius = 1; + guess = FALSE; + goto noguess; + } + return FALSE; } +found: u.dx = 0; u.dy = 0; nomul(0); + return FALSE; } void @@ -731,11 +838,13 @@ xchar chainx, chainy, ballx, bally; /* ball&chain new positions */ int bc_control; /* control for ball&chain */ boolean cause_delay = FALSE; /* dragging ball will skip a move */ + const char *predicament; u_wipe_engr(rnd(5)); - if ( flags.travel ) - findtravelpath(); + if (flags.travel) + if (!findtravelpath(FALSE)) + (void) findtravelpath(TRUE); if(((wtcap = near_capacity()) >= OVERLOADED || (wtcap > SLT_ENCUMBER && @@ -821,7 +930,10 @@ nomul(0); return; } - if((trap = t_at(x, y)) && trap->tseen) { + if (((trap = t_at(x, y)) && trap->tseen) || + (Blind && !Levitation && !Flying && + !is_clinger(youmonst.data) && + (is_pool(x, y) || is_lava(x, y)) && levl[x][y].seenv)) { if(flags.run >= 2) { nomul(0); flags.move = 0; @@ -952,13 +1064,20 @@ if (flags.forcefight || /* remembered an 'I' && didn't use a move command */ (glyph_is_invisible(levl[x][y].glyph) && !flags.nopick)) { + boolean expl = (Upolyd && attacktype(youmonst.data, AT_EXPL)); char buf[BUFSZ]; Sprintf(buf,"a vacant spot on the %s", surface(x,y)); - You("attack %s.", - !Underwater ? "thin air" : is_pool(x,y) ? "empty water" : buf); + You("%s %s.", + expl ? "explode at" : "attack", + !Underwater ? "thin air" : + is_pool(x,y) ? "empty water" : buf); unmap_object(x, y); /* known empty -- remove 'I' if present */ newsym(x, y); nomul(0); + if (expl) { + u.mh = -1; /* dead in the current form */ + rehumanize(); + } return; } if (glyph_is_invisible(levl[x][y].glyph)) { @@ -968,10 +1087,7 @@ /* not attacking an animal, so we try to move */ #ifdef STEED if (u.usteed && !u.usteed->mcanmove && (u.dx || u.dy)) { - pline("%s won't move!", - upstart(x_monnam(u.usteed, - u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - (char *)0, SUPPRESS_SADDLE, FALSE))); + pline("%s won't move!", upstart(y_monnam(u.usteed))); nomul(0); return; } else @@ -1003,10 +1119,8 @@ } else if (flags.verbose) { #ifdef STEED if (u.usteed) - Norep("%s is still in a pit.", - upstart(x_monnam(u.usteed, - u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - (char *)0, SUPPRESS_SADDLE, FALSE))); + Norep("%s is still in a pit.", + upstart(y_monnam(u.usteed))); else #endif Norep( (Hallucination && !rn2(5)) ? @@ -1015,14 +1129,11 @@ } } else if (u.utraptype == TT_LAVA) { if(flags.verbose) { - char *predicament = "stuck in the lava"; + predicament = "stuck in the lava"; #ifdef STEED if (u.usteed) - Norep("%s is %s.", - upstart(x_monnam(u.usteed, - u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - (char *)0, SUPPRESS_SADDLE, FALSE)), - predicament); + Norep("%s is %s.", upstart(y_monnam(u.usteed)), + predicament); else #endif Norep("You are %s.", predicament); @@ -1033,9 +1144,7 @@ #ifdef STEED if (u.usteed) You("lead %s to the edge of the lava.", - x_monnam(u.usteed, - u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - (char *)0, SUPPRESS_SADDLE, FALSE)); + y_monnam(u.usteed)); else #endif You("pull yourself to the edge of the lava."); @@ -1051,14 +1160,11 @@ } if(--u.utrap) { if(flags.verbose) { - char *predicament = "stuck to the web"; + predicament = "stuck to the web"; #ifdef STEED if (u.usteed) - Norep("%s is %s.", - upstart(x_monnam(u.usteed, - u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - (char *)0, SUPPRESS_SADDLE, FALSE)), - predicament); + Norep("%s is %s.", upstart(y_monnam(u.usteed)), + predicament); else #endif Norep("You are %s.", predicament); @@ -1066,10 +1172,8 @@ } else { #ifdef STEED if (u.usteed) - pline("%s breaks out of the web.", - upstart(x_monnam(u.usteed, - u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - (char *)0, SUPPRESS_SADDLE, FALSE))); + pline("%s breaks out of the web.", + upstart(y_monnam(u.usteed))); else #endif You("disentangle yourself."); @@ -1077,39 +1181,33 @@ } else if (u.utraptype == TT_INFLOOR) { if(--u.utrap) { if(flags.verbose) { - char *predicament = "stuck in the"; + predicament = "stuck in the"; #ifdef STEED if (u.usteed) - Norep("%s is %s %s.", - upstart(x_monnam(u.usteed, - u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - (char *)0, SUPPRESS_SADDLE, FALSE)), - predicament, surface(u.ux, u.uy)); + Norep("%s is %s %s.", + upstart(y_monnam(u.usteed)), + predicament, surface(u.ux, u.uy)); else #endif - Norep("You are %s %s.", predicament, surface(u.ux, u.uy)); + Norep("You are %s %s.", predicament, + surface(u.ux, u.uy)); } } else { #ifdef STEED if (u.usteed) - pline("%s finally wiggles free.", - upstart(x_monnam(u.usteed, - u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - (char *)0, SUPPRESS_SADDLE, FALSE))); + pline("%s finally wiggles free.", + upstart(y_monnam(u.usteed))); else #endif You("finally wiggle free."); } } else { if(flags.verbose) { - char *predicament = "caught in a bear trap"; + predicament = "caught in a bear trap"; #ifdef STEED if (u.usteed) - Norep("%s is %s.", - upstart(x_monnam(u.usteed, - u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - (char *)0, SUPPRESS_SADDLE, FALSE)), - predicament); + Norep("%s is %s.", upstart(y_monnam(u.usteed)), + predicament); else #endif Norep("You are %s.", predicament); @@ -1119,7 +1217,7 @@ return; } - if ( !test_move( u.ux, u.uy, x-u.ux, y-u.uy, 0 ) ) { + if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) { flags.move = 0; nomul(0); return; @@ -1128,7 +1226,7 @@ /* Move ball and chain. */ if (Punished) if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy, - &cause_delay)) + &cause_delay, TRUE)) return; /* Check regions entering/leaving */ @@ -1182,6 +1280,13 @@ sobj_at(BOULDER, trap->tx, trap->ty)) { /* can't swap places with pet pinned in a pit by a boulder */ u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ + } else if (u.ux0 != x && u.uy0 != y && + bad_rock(mtmp->data, x, u.uy0) && + bad_rock(mtmp->data, u.ux0, y) && + (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { + /* can't swap places when pet won't fit thru the opening */ + u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ + You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); } else { char pnambuf[BUFSZ]; @@ -1271,6 +1376,21 @@ nomul(-2); nomovemsg = ""; } + + if (flags.run && iflags.runmode != RUN_TPORT) { + /* display every step or every 7th step depending upon mode */ + if (iflags.runmode != RUN_LEAP || !(moves % 7L)) { + if (flags.time) flags.botl = 1; + curs_on_u(); + delay_output(); + if (iflags.runmode == RUN_CRAWL) { + delay_output(); + delay_output(); + delay_output(); + delay_output(); + } + } + } } void @@ -1278,10 +1398,18 @@ { /* a special clue-msg when on the Invocation position */ if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { + char buf[BUFSZ]; struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION); - You_feel("a strange vibration under your %s.", - makeplural(body_part(FOOT))); + nomul(0); /* stop running or travelling */ +#ifdef STEED + if (u.usteed) Sprintf(buf, "beneath %s", y_monnam(u.usteed)); + else +#endif + if (Levitation || Flying) Strcpy(buf, "beneath you"); + else Sprintf(buf, "under your %s", makeplural(body_part(FOOT))); + + You_feel("a strange vibration %s.", buf); if (otmp && otmp->spe == 7 && otmp->lamplit) pline("%s %s!", The(xname(otmp)), Blind ? "throbs palpably" : "glows with a strange light"); @@ -1366,7 +1494,7 @@ Amonnam(mtmp), ceiling(u.ux,u.uy)); if(mtmp->mtame) /* jumps to greet you, not attack */ ; - else if(uarmh) + else if(uarmh && is_metallic(uarmh)) pline("Its blow glances off your helmet."); else if (u.uac + 3 <= rnd(20)) You("are almost hit by %s!", @@ -1480,6 +1608,31 @@ return(ptr); } +/* is (x,y) in a town? */ +boolean +in_town(x, y) +register int x, y; +{ + s_level *slev = Is_special(&u.uz); + register struct mkroom *sroom; + boolean has_subrooms = FALSE; + + if (!slev || !slev->flags.town) return FALSE; + + /* + * See if (x,y) is in a room with subrooms, if so, assume it's the + * town. If there are no subrooms, the whole level is in town. + */ + for (sroom = &rooms[0]; sroom->hx > 0; sroom++) { + if (sroom->nsubrooms > 0) { + has_subrooms = TRUE; + if (inside_room(sroom, x, y)) return TRUE; + } + } + + return !has_subrooms; +} + STATIC_OVL void move_update(newlev) register boolean newlev; @@ -1690,8 +1843,8 @@ if (!can_reach_floor()) { #ifdef STEED if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) - You("aren't skilled enough to reach from %s.", - mon_nam(u.usteed)); + You("aren't skilled enough to reach from %s.", + y_monnam(u.usteed)); else #endif You("cannot reach the %s.", surface(u.ux,u.uy)); @@ -1865,7 +2018,8 @@ } /* called when a non-movement, multi-turn action has completed */ -void unmul(msg_override) +void +unmul(msg_override) const char *msg_override; { multi = 0; /* caller will usually have done this already */ @@ -1992,14 +2146,14 @@ of invent for easier manipulation by askchain & co, but it's also retained in u.ugold in order to keep the status line accurate; we mustn't add its weight in twice under that circumstance */ - wt = (otmp && otmp->oclass == GOLD_CLASS) ? 0 : + wt = (otmp && otmp->oclass == COIN_CLASS) ? 0 : (int)((u.ugold + 50L) / 100L); #endif while (otmp) { #ifndef GOLDOBJ if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data)) #else - if (otmp->oclass == GOLD_CLASS) + if (otmp->oclass == COIN_CLASS) wt += (int)(((long)otmp->quan + 50L) / 100L); else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data)) #endif @@ -2075,12 +2229,13 @@ /* Intended use is for your or some monsters inventory, */ /* now that u.gold/m.gold is gone.*/ /* Counting money in a container might be possible too. */ -long money_cnt(otmp) +long +money_cnt(otmp) struct obj *otmp; { while(otmp) { /* Must change when silver & copper is implemented: */ - if (otmp->oclass == GOLD_CLASS) return otmp->quan; + if (otmp->oclass == COIN_CLASS) return otmp->quan; otmp = otmp->nobj; } return 0; diff -Naurd ../nethack-3.4.0/src/hacklib.c ./src/hacklib.c --- ../nethack-3.4.0/src/hacklib.c Wed Mar 20 23:43:06 2002 +++ ./src/hacklib.c Mon Feb 24 15:25:05 2003 @@ -18,6 +18,7 @@ char * upstart (char *) char * mungspaces (char *) char * eos (char *) + char * strkitten (char *,char) char * s_suffix (const char *) char * xcrypt (const char *, char *) boolean onlyspace (const char *) @@ -130,6 +131,19 @@ return s; } +/* strcat(s, {c,'\0'}); */ +char * +strkitten(s, c) /* append a character to a string (in place) */ + char *s; + char c; +{ + char *p = eos(s); + + *p++ = c; + *p = '\0'; + return s; +} + char * s_suffix(s) /* return a name converted to possessive */ const char *s; diff -Naurd ../nethack-3.4.0/src/invent.c ./src/invent.c --- ../nethack-3.4.0/src/invent.c Wed Mar 20 23:43:07 2002 +++ ./src/invent.c Mon Feb 24 15:25:05 2003 @@ -1,9 +1,8 @@ -/* SCCS Id: @(#)invent.c 3.4 2002/02/23 */ +/* SCCS Id: @(#)invent.c 3.4 2003/01/24 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" -#include "artifact.h" #define NOINVSYM '#' #define CONTAINED_SYM '>' /* designator for inside a container */ @@ -55,7 +54,7 @@ #ifdef GOLDOBJ /* There is only one of these in inventory... */ - if (otmp->oclass == GOLD_CLASS) { + if (otmp->oclass == COIN_CLASS) { otmp->invlet = GOLD_SYM; return; } @@ -179,7 +178,7 @@ #ifdef GOLDOBJ /* temporary special case for gold objects!!!! */ #endif - if (otmp->oclass == GOLD_CLASS) otmp->owt = weight(otmp); + if (otmp->oclass == COIN_CLASS) otmp->owt = weight(otmp); else otmp->owt += obj->owt; if(!otmp->onamelth && obj->onamelth) otmp = *potmp = oname(otmp, ONAME(obj)); @@ -245,7 +244,7 @@ addinv_core1(obj) struct obj *obj; { - if (obj->oclass == GOLD_CLASS) { + if (obj->oclass == COIN_CLASS) { #ifndef GOLDOBJ u.ugold += obj->quan; #else @@ -287,8 +286,7 @@ addinv_core2(obj) struct obj *obj; { - if (obj->otyp == LUCKSTONE || - (obj->oartifact && spec_ability(obj, SPFX_LUCK))) { + if (confers_luck(obj)) { /* new luckstone must be in inventory by this point * for correct calculation */ set_moreluck(); @@ -312,7 +310,7 @@ addinv_core1(obj); #ifndef GOLDOBJ /* if handed gold, we're done */ - if (obj->oclass == GOLD_CLASS) + if (obj->oclass == COIN_CLASS) return obj; #endif @@ -365,10 +363,12 @@ #endif /* OVL1 */ #ifdef OVLB -/* Add an item to the inventory unless we're fumbling, and give a message. +/* Add an item to the inventory unless we're fumbling or it refuses to be + * held (via touch_artifact), and give a message. * If there aren't any free inventory slots, we'll drop it instead. * If both success and failure messages are NULL, then we're just doing the - * fumbling/slot-limit checking for a silent grab. + * fumbling/slot-limit checking for a silent grab. In any case, + * touch_artifact will print its own messages if they are warranted. */ struct obj * hold_another_object(obj, drop_fmt, drop_arg, hold_msg) @@ -378,39 +378,62 @@ char buf[BUFSZ]; if (!Blind) obj->dknown = 1; /* maximize mergibility */ - if (Fumbling) { + if (obj->oartifact) { + /* place_object may change these */ + boolean crysknife = (obj->otyp == CRYSKNIFE); + int oerode = obj->oerodeproof; + boolean wasUpolyd = Upolyd; + + /* in case touching this object turns out to be fatal */ + place_object(obj, u.ux, u.uy); + + if (!touch_artifact(obj, &youmonst)) { + obj_extract_self(obj); /* remove it from the floor */ + dropy(obj); /* now put it back again :-) */ + return obj; + } else if (wasUpolyd && !Upolyd) { + /* loose your grip if you revert your form */ if (drop_fmt) pline(drop_fmt, drop_arg); + obj_extract_self(obj); dropy(obj); + return obj; + } + obj_extract_self(obj); + if (crysknife) { + obj->otyp = CRYSKNIFE; + obj->oerodeproof = oerode; + } + } + if (Fumbling) { + if (drop_fmt) pline(drop_fmt, drop_arg); + dropy(obj); } else { - long oquan = obj->quan; - int prev_encumbr = near_capacity(); /* before addinv() */ - /* encumbrance only matters if it would now become worse - than max( current_value, stressed ) */ - if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER; - if (drop_arg) { - /* addinv() may redraw the entire inventory, overwriting - * drop_arg when it comes from something like doname() - */ - Strcpy(buf, drop_arg); - drop_arg = buf; - } - obj = addinv(obj); - if (inv_cnt() > 52 + long oquan = obj->quan; + int prev_encumbr = near_capacity(); /* before addinv() */ + + /* encumbrance only matters if it would now become worse + than max( current_value, stressed ) */ + if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER; + /* addinv() may redraw the entire inventory, overwriting + drop_arg when it comes from something like doname() */ + if (drop_arg) drop_arg = strcpy(buf, drop_arg); + + obj = addinv(obj); + if (inv_cnt() > 52 || ((obj->otyp != LOADSTONE || !obj->cursed) && near_capacity() > prev_encumbr)) { - if (drop_fmt) pline(drop_fmt, drop_arg); - /* undo any merge which took place */ - if (obj->quan > oquan) { - obj = splitobj(obj, oquan); - } - dropx(obj); - } else { - if (flags.autoquiver && !uquiver && - (is_missile(obj) || - (uwep && ammo_and_launcher(obj, uwep)))) - setuqwep(obj); - if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan); - } + if (drop_fmt) pline(drop_fmt, drop_arg); + /* undo any merge which took place */ + if (obj->quan > oquan) obj = splitobj(obj, oquan); + dropx(obj); + } else { + if (flags.autoquiver && !uquiver && !obj->owornmask && + (is_missile(obj) || + ammo_and_launcher(obj, uwep) || + ammo_and_launcher(obj, uswapwep))) + setuqwep(obj); + if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan); + } } return obj; } @@ -455,9 +478,10 @@ freeinv_core(obj) struct obj *obj; { - if (obj->oclass == GOLD_CLASS) { + if (obj->oclass == COIN_CLASS) { #ifndef GOLDOBJ u.ugold -= obj->quan; + obj->in_use = FALSE; #endif flags.botl = 1; return; @@ -484,8 +508,7 @@ if (obj->otyp == LOADSTONE) { curse(obj); - } else if (obj->otyp == LUCKSTONE || - (obj->oartifact && spec_ability(obj, SPFX_LUCK))) { + } else if (confers_luck(obj)) { set_moreluck(); flags.botl = 1; } else if (obj->otyp == FIGURINE && obj->timed) { @@ -633,7 +656,7 @@ { register struct obj *obj = level.objects[x][y]; while(obj) { - if (obj->oclass == GOLD_CLASS) return obj; + if (obj->oclass == COIN_CLASS) return obj; obj = obj->nexthere; } return((struct obj *)0); @@ -733,6 +756,7 @@ boolean usegold = FALSE; /* can't use gold because its illegal */ boolean allowall = FALSE; boolean allownone = FALSE; + boolean useboulder = FALSE; xchar foox = 0; long cnt; boolean prezero = FALSE; @@ -740,14 +764,16 @@ if(*let == ALLOW_COUNT) let++, allowcnt = 1; #ifndef GOLDOBJ - if(*let == GOLD_CLASS) let++, + if(*let == COIN_CLASS) let++, usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE); #else - if(*let == GOLD_CLASS) let++, usegold = TRUE; + if(*let == COIN_CLASS) let++, usegold = TRUE; #endif /* Equivalent of an "ugly check" for gold */ - if (usegold && !strcmp(word, "eat") && !metallivorous(youmonst.data)) + if (usegold && !strcmp(word, "eat") && + (!metallivorous(youmonst.data) + || youmonst.data == &mons[PM_RUST_MONSTER])) #ifndef GOLDOBJ usegold = allowgold = FALSE; #else @@ -764,9 +790,14 @@ */ if(allowall && !strcmp(word, "read")) allowall = FALSE; + /* another ugly check: show boulders (not statues) */ + if(*let == WEAPON_CLASS && + !strcmp(word, "throw") && throws_rocks(youmonst.data)) + useboulder = TRUE; + if(allownone) *bp++ = '-'; #ifndef GOLDOBJ - if(allowgold) *bp++ = def_oc_syms[GOLD_CLASS]; + if(allowgold) *bp++ = def_oc_syms[COIN_CLASS]; #endif if(bp > buf && bp[-1] == '-') *bp++ = ' '; ap = altlets; @@ -782,6 +813,7 @@ #ifdef GOLDOBJ || (usegold && otmp->invlet == GOLD_SYM) #endif + || (useboulder && otmp->otyp == BOULDER) ) { register int otyp = otmp->otyp; bp[foo++] = otmp->invlet; @@ -797,10 +829,12 @@ || (putting_on(word) && (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) /* already worn */ +#if 0 /* 3.4.1 -- include currently wielded weapon among the choices */ || (!strcmp(word, "wield") && (otmp->owornmask & W_WEP)) +#endif || (!strcmp(word, "ready") && - (otmp->owornmask & (W_WEP | W_SWAPWEP | W_QUIVER))) + (otmp == uwep || (otmp == uswapwep && u.twoweap))) ) { foo--; foox++; @@ -829,17 +863,22 @@ otyp != OIL_LAMP && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN) || (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) + || (!strncmp(word, "rub on the stone", 16) && + *let == GEM_CLASS && /* using known touchstone */ + otmp->dknown && objects[otyp].oc_name_known) || ((!strcmp(word, "use or apply") || !strcmp(word, "untrap with")) && /* Picks, axes, pole-weapons, bullwhips */ ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) && - !is_pole(otmp) && otyp != BULLWHIP) - || (otmp->oclass == POTION_CLASS && + !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) || + (otmp->oclass == POTION_CLASS && /* only applicable potion is oil, and it will only be offered as a choice when already discovered */ (otyp != POT_OIL || !otmp->dknown || - !objects[POT_OIL].oc_name_known)) - || (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) + !objects[POT_OIL].oc_name_known)) || + (otmp->oclass == FOOD_CLASS && + otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) || + (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) || (!strcmp(word, "invoke") && (!otmp->oartifact && !objects[otyp].oc_unique && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) && @@ -927,7 +966,7 @@ if(ilet == '-') { return(allownone ? &zeroobj : (struct obj *) 0); } - if(ilet == def_oc_syms[GOLD_CLASS]) { + if(ilet == def_oc_syms[COIN_CLASS]) { if (!usegold) { You("cannot %s gold.", word); return(struct obj *)0; @@ -981,7 +1020,7 @@ * counts for other things since the throw code will * split off a single item anyway */ #ifdef GOLDOBJ - if (ilet != def_oc_syms[GOLD_CLASS]) + if (ilet != def_oc_syms[COIN_CLASS]) #endif allowcnt = 1; if(cnt == 0 && prezero) return((struct obj *)0); @@ -1016,10 +1055,10 @@ } if(!allowall && let && !index(let,otmp->oclass) #ifdef GOLDOBJ - && !(usegold && otmp->oclass == GOLD_CLASS) + && !(usegold && otmp->oclass == COIN_CLASS) #endif ) { - pline(silly_thing_to, word); + silly_thing(word, otmp); return((struct obj *)0); } if(allowcnt == 2) { /* cnt given */ @@ -1038,6 +1077,39 @@ return(otmp); } +void +silly_thing(word, otmp) +const char *word; +struct obj *otmp; +{ + int otyp = otmp->otyp; + boolean domsg = FALSE; + const char *s1, *s2, *s3; + const char *what = (otmp->quan > 1L) ? "one of those" : "that"; + if ((!strcmp(word, "wear") || !strcmp(word, "take off")) && + (otmp->oclass == RING_CLASS || + (otmp->oclass == FOOD_CLASS && otmp->otyp == MEAT_RING) || + (otmp->oclass == TOOL_CLASS && + (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)))) { + if (!strcmp(word, "wear")) { + s1 = "P"; s2 = "put"; s3 = " on"; domsg = TRUE; + } else { + s1 = "R"; s2 = "remove"; s3 = ""; domsg = TRUE; + } + } else if ((!strcmp(word, "put on") || !strcmp(word, "remove")) && + (otmp->oclass == ARMOR_CLASS)) { + if (!strcmp(word, "remove")) { + s1 = "T"; s2 = "take"; s3 = " off"; domsg = TRUE; + } else { + s1 = "W"; s2 = "wear"; s3 = ""; domsg = TRUE; + } + } + if (domsg) + pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3); + else + pline(silly_thing_to, word); +} + #endif /* OVL1 */ #ifdef OVLB @@ -1093,12 +1165,14 @@ int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0; boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0; boolean takeoff, ident, allflag, m_seen; + int itemcount; #ifndef GOLDOBJ int oletct, iletct, allowgold, unpaid, oc_of_sym; #else int oletct, iletct, unpaid, oc_of_sym; #endif char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5]; + char extra_removeables[3+1]; /* uwep,uswapwep,uquiver */ char buf[BUFSZ], qbuf[QBUFSZ]; if (resultflags) *resultflags = 0; @@ -1128,7 +1202,7 @@ #ifndef GOLDOBJ (allowgold != 0), #endif - filter); + filter, &itemcount); unpaid = count_unpaid(invent); if (ident && !iletct) { @@ -1160,20 +1234,31 @@ break; } + extra_removeables[0] = '\0'; + if (takeoff) { + /* arbitrary types of items can be placed in the weapon slots + [any duplicate entries in extra_removeables[] won't matter] */ + if (uwep) (void)strkitten(extra_removeables, uwep->oclass); + if (uswapwep) (void)strkitten(extra_removeables, uswapwep->oclass); + if (uquiver) (void)strkitten(extra_removeables, uquiver->oclass); + } + ip = buf; olets[oletct = 0] = '\0'; while ((sym = *ip++) != '\0') { if (sym == ' ') continue; oc_of_sym = def_char_to_objclass(sym); - if (takeoff && !(uwep && oc_of_sym == uwep->oclass) && - (oc_of_sym != MAXOCLASSES)) { - if (!index(removeables, oc_of_sym)) { + if (takeoff && oc_of_sym != MAXOCLASSES) { + if (index(extra_removeables, oc_of_sym)) { + ; /* skip rest of takeoff checks */ + } else if (!index(removeables, oc_of_sym)) { pline("Not applicable."); return 0; } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) { You("are not wearing any armor."); return 0; - } else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep && !uquiver) { + } else if (oc_of_sym == WEAPON_CLASS && + !uwep && !uswapwep && !uquiver) { You("are not wielding anything."); return 0; } else if (oc_of_sym == RING_CLASS && !uright && !uleft) { @@ -1188,7 +1273,7 @@ } } - if (oc_of_sym == GOLD_CLASS && !combo) { + if (oc_of_sym == COIN_CLASS && !combo) { #ifndef GOLDOBJ if (allowgold == 1) (*fn)(mkgoldobj(u.ugold)); @@ -1271,7 +1356,7 @@ register const char *olets, *word; /* olets is an Obj Class char array */ register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P)); { - register struct obj *otmp, *otmp2; + struct obj *otmp, *otmp2, *otmpo; register char sym, ilet; register int cnt = 0, dud = 0, tmp; boolean takeoff, nodot, ident, ininv; @@ -1288,7 +1373,7 @@ */ nextclass: ilet = 'a'-1; - if (*objchn && (*objchn)->oclass == GOLD_CLASS) + if (*objchn && (*objchn)->oclass == COIN_CLASS) ilet--; /* extra iteration */ for (otmp = *objchn; otmp; otmp = otmp2) { if(ilet == 'z') ilet = 'A'; else ilet++; @@ -1306,6 +1391,7 @@ } else sym = 'y'; + otmpo = otmp; if (sym == '#') { /* Number was entered; split the object unless it corresponds to 'none' or 'all'. 2 special cases: cursed loadstones and @@ -1328,7 +1414,13 @@ allflag = 1; case 'y': tmp = (*fn)(otmp); - if(tmp < 0) goto ret; + if(tmp < 0) { + if (otmp != otmpo) { + /* split occurred, merge again */ + (void) merged(&otmpo, &otmp); + } + goto ret; + } cnt += tmp; if(--mx == 0) goto ret; case 'n': @@ -1454,7 +1546,7 @@ register struct obj *obj; { #ifndef GOLDOBJ - if (obj->oclass == GOLD_CLASS) + if (obj->oclass == COIN_CLASS) return GOLD_SYM; #endif if (!flags.invlet_constant) { @@ -1516,7 +1608,7 @@ (dot && use_invlet ? obj->invlet : let), (txt ? txt : doname(obj)), cost, currency(cost)); #ifndef GOLDOBJ - } else if (obj && obj->oclass == GOLD_CLASS) { + } else if (obj && obj->oclass == COIN_CLASS) { Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan), (dot ? "." : "")); #endif @@ -1637,6 +1729,7 @@ ret = message_menu(lets[0], want_reply ? PICK_ONE : PICK_NONE, xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L)); + if (out_cnt) *out_cnt = -1L; /* select all */ break; } } @@ -1732,22 +1825,23 @@ int count = 0; while (list) { + if (Role_if(PM_PRIEST)) list->bknown = TRUE; switch(type) { case BUC_BLESSED: - if (list->oclass != GOLD_CLASS && list->bknown && list->blessed) + if (list->oclass != COIN_CLASS && list->bknown && list->blessed) count++; break; case BUC_CURSED: - if (list->oclass != GOLD_CLASS && list->bknown && list->cursed) + if (list->oclass != COIN_CLASS && list->bknown && list->cursed) count++; break; case BUC_UNCURSED: - if (list->oclass != GOLD_CLASS && + if (list->oclass != COIN_CLASS && list->bknown && !list->blessed && !list->cursed) count++; break; case BUC_UNKNOWN: - if (list->oclass != GOLD_CLASS && !list->bknown) + if (list->oclass != COIN_CLASS && !list->bknown) count++; break; default: @@ -1864,7 +1958,7 @@ char c = '\0'; int n, i = 0; char *extra_types, types[BUFSZ]; - int class_count, oclass, unpaid_count; + int class_count, oclass, unpaid_count, itemcount; boolean billx = *u.ushops && doinvbill(0); menu_item *pick_list; boolean traditional = TRUE; @@ -1899,7 +1993,7 @@ #ifndef GOLDOBJ (u.ugold != 0), #endif - (boolean FDECL((*),(OBJ_P))) 0); + (boolean FDECL((*),(OBJ_P))) 0, &itemcount); if (unpaid_count) { Strcat(types, "u"); class_count++; @@ -1955,7 +2049,7 @@ } if (traditional) { oclass = def_char_to_objclass(c); /* change to object class */ - if (oclass == GOLD_CLASS) { + if (oclass == COIN_CLASS) { return doprgold(); } else if (index(types, c) > index(types, '\033')) { You("have no such objects."); @@ -2083,9 +2177,14 @@ if (Blind) { boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz); - You("try to feel what is %s%s.", - drift ? "floating here" : "lying here on the ", - drift ? "" : surface(u.ux, u.uy)); + if (dfeature && !strncmp(dfeature, "altar ", 6)) { + /* don't say "altar" twice, dfeature has more info */ + You("try to feel what is here."); + } else { + You("try to feel what is %s%s.", + drift ? "floating here" : "lying here on the ", + drift ? "" : surface(u.ux, u.uy)); + } if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy))) dfeature = 0; /* ice already identifed */ if (!can_reach_floor()) { @@ -2186,16 +2285,12 @@ mergable(otmp, obj) /* returns TRUE if obj & otmp can be merged */ register struct obj *otmp, *obj; { -#ifndef GOLDOBJ - if (obj->otyp != otmp->otyp || obj->unpaid != otmp->unpaid || -#else if (obj->otyp != otmp->otyp) return FALSE; - - /* Coins of the same kind will always merge. */ - if (obj->oclass == GOLD_CLASS) return TRUE; - - if (obj->unpaid != otmp->unpaid || +#ifdef GOLDOBJ + /* coins of the same kind will always merge */ + if (obj->oclass == COIN_CLASS) return TRUE; #endif + if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe || obj->dknown != otmp->dknown || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed || @@ -2682,7 +2777,7 @@ * gold in their inventory, so it won't merge. */ m_gold = zeroobj; - m_gold.otyp = GOLD_PIECE; m_gold.oclass = GOLD_CLASS; + m_gold.otyp = GOLD_PIECE; m_gold.oclass = COIN_CLASS; m_gold.quan = mon->mgold; m_gold.dknown = 1; m_gold.where = OBJ_FREE; /* we had better not merge and free this object... */ diff -Naurd ../nethack-3.4.0/src/lock.c ./src/lock.c --- ../nethack-3.4.0/src/lock.c Wed Mar 20 23:43:07 2002 +++ ./src/lock.c Mon Feb 24 15:25:05 2003 @@ -226,7 +226,8 @@ pick_lock(pick) /* pick a lock with a given object */ register struct obj *pick; { - int x, y, picktyp, c, ch; + int picktyp, c, ch; + coord cc; struct rm *door; struct obj *otmp; char qbuf[QBUFSZ]; @@ -270,12 +271,10 @@ impossible("picking lock with object %d?", picktyp); return(0); } - if(!getdir((char *)0)) return(0); - ch = 0; /* lint suppression */ - x = u.ux + u.dx; - y = u.uy + u.dy; - if (x == u.ux && y == u.uy) { /* pick lock on a container */ + + if(!get_adjacent_loc((char *)0, "Invalid location!", u.ux, u.uy, &cc)) return 0; + if (cc.x == u.ux && cc.y == u.uy) { /* pick lock on a container */ const char *verb; boolean it; int count; @@ -295,7 +294,7 @@ count = 0; c = 'n'; /* in case there are no boxes here */ - for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) + for(otmp = level.objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { ++count; if (!can_reach_floor()) { @@ -354,8 +353,8 @@ } else { /* pick the lock in a door */ struct monst *mtmp; - door = &levl[x][y]; - if ((mtmp = m_at(x, y)) && canseemon(mtmp) + door = &levl[cc.x][cc.y]; + if ((mtmp = m_at(cc.x, cc.y)) && canseemon(mtmp) && mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT) { #ifdef TOURIST @@ -368,7 +367,7 @@ return(0); } if(!IS_DOOR(door->typ)) { - if (is_drawbridge_wall(x,y) >= 0) + if (is_drawbridge_wall(cc.x,cc.y) >= 0) You("%s no lock on the drawbridge.", Blind ? "feel" : "see"); else @@ -490,7 +489,7 @@ int doopen() /* try to open a door */ { - register int x, y; + coord cc; register struct rm *door; struct monst *mtmp; @@ -504,13 +503,11 @@ return 0; } - if(!getdir((char *)0)) return(0); + if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return(0); - x = u.ux + u.dx; - y = u.uy + u.dy; - if((x == u.ux) && (y == u.uy)) return(0); + if((cc.x == u.ux) && (cc.y == u.uy)) return(0); - if ((mtmp = m_at(x,y)) && + if ((mtmp = m_at(cc.x,cc.y)) && mtmp->m_ap_type == M_AP_FURNITURE && (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) && @@ -520,10 +517,10 @@ return(1); } - door = &levl[x][y]; + door = &levl[cc.x][cc.y]; if(!IS_DOOR(door->typ)) { - if (is_db_wall(x,y)) { + if (is_db_wall(cc.x,cc.y)) { There("is no obvious way to open the drawbridge."); return(0); } @@ -542,7 +539,7 @@ default: mesg = " is locked"; break; } pline("This door%s.", mesg); - if (Blind) feel_location(x,y); + if (Blind) feel_location(cc.x,cc.y); return(0); } @@ -557,14 +554,14 @@ if(door->doormask & D_TRAPPED) { b_trapped("door", FINGER); door->doormask = D_NODOOR; - if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L); + if (*in_rooms(cc.x, cc.y, SHOPBASE)) add_damage(cc.x, cc.y, 0L); } else door->doormask = D_ISOPEN; if (Blind) - feel_location(x,y); /* the hero knows she opened it */ + feel_location(cc.x,cc.y); /* the hero knows she opened it */ else - newsym(x,y); - unblock_point(x,y); /* vision: new see through there */ + newsym(cc.x,cc.y); + unblock_point(cc.x,cc.y); /* vision: new see through there */ } else { exercise(A_STR, TRUE); pline_The("door resists!"); @@ -847,6 +844,8 @@ } unblock_point(x,y); newsym(x,y); + /* force vision recalc before printing more messages */ + if (vision_full_recalc) vision_recalc(0); loudness = 20; } else res = FALSE; break; @@ -872,12 +871,12 @@ chest_shatter_msg(otmp) struct obj *otmp; { - const char *disposition, *article = (otmp->quan > 1L) ? "A" : "The"; + const char *disposition; const char *thing; long save_Blinded; if (otmp->oclass == POTION_CLASS) { - You("%s a %s shatter!", Blind ? "hear" : "see", bottlename()); + You("%s %s shatter!", Blind ? "hear" : "see", an(bottlename())); if (!breathless(youmonst.data) || haseyes(youmonst.data)) potionbreathe(otmp); return; @@ -904,7 +903,7 @@ default: disposition = "is destroyed"; break; } - pline("%s %s %s!", article, thing, disposition); + pline("%s %s!", An(thing), disposition); } #endif /* OVLB */ diff -Naurd ../nethack-3.4.0/src/makemon.c ./src/makemon.c --- ../nethack-3.4.0/src/makemon.c Wed Mar 20 23:43:08 2002 +++ ./src/makemon.c Mon Feb 24 15:25:05 2003 @@ -407,13 +407,6 @@ case PM_HORNED_DEVIL: (void)mongets(mtmp, rn2(4) ? TRIDENT : BULLWHIP); break; - case PM_ICE_DEVIL: - if (!rn2(4)) (void)mongets(mtmp, SPEAR); - break; - case PM_ASMODEUS: - (void)mongets(mtmp, WAN_COLD); - (void)mongets(mtmp, WAN_FIRE); - break; case PM_DISPATER: (void)mongets(mtmp, WAN_STRIKING); break; @@ -642,6 +635,16 @@ mkmonmoney(mtmp, (long) d(level_difficulty(), 30)); #endif break; + case S_DEMON: + /* moved here from m_initweap() because these don't + have AT_WEAP so m_initweap() is not called for them */ + if (ptr == &mons[PM_ICE_DEVIL] && !rn2(4)) { + (void)mongets(mtmp, SPEAR); + } else if (ptr == &mons[PM_ASMODEUS]) { + (void)mongets(mtmp, WAN_COLD); + (void)mongets(mtmp, WAN_FIRE); + } + break; default: break; } @@ -763,6 +766,7 @@ boolean byyou = (x == u.ux && y == u.uy); boolean allow_minvent = ((mmflags & NO_MINVENT) == 0); boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0); + unsigned gpflags = (mmflags & MM_IGNOREWATER) ? MM_IGNOREWATER : 0; uchar lim; /* if caller wants random location, do it here */ @@ -774,12 +778,12 @@ do { x = rn1(COLNO-3,2); y = rn2(ROWNO); - } while(!goodpos(x, y, ptr ? &fakemon : (struct monst *)0) || + } while(!goodpos(x, y, ptr ? &fakemon : (struct monst *)0, gpflags) || (!in_mklev && tryct++ < 50 && cansee(x, y))); } else if (byyou && !in_mklev) { coord bypos; - if(enexto(&bypos, u.ux, u.uy, ptr)) { + if(enexto_core(&bypos, u.ux, u.uy, ptr, gpflags)) { x = bypos.x; y = bypos.y; } else @@ -816,7 +820,7 @@ return((struct monst *) 0); /* no more monsters! */ } fakemon.data = ptr; /* set up for goodpos */ - } while(!goodpos(x, y, &fakemon) && tryct++ < 50); + } while(!goodpos(x, y, &fakemon, gpflags) && tryct++ < 50); mndx = monsndx(ptr); } /* if it's unique, don't ever make it again */ @@ -830,8 +834,8 @@ * the caller manually decrement mvitals if the monster is created * under circumstances where one would not logically expect the * creation to reduce the supply of wild monsters. Monster cloning - * might be one such case, but we go against logic there in order to - * reduce the possibility of abuse. + * might be one case that requires that in order to reduce the + * possibility of abuse, but currently doesn't. */ if (mvitals[mndx].born < 255 && countbirth) mvitals[mndx].born++; lim = mbirth_limit(mndx); @@ -893,7 +897,7 @@ if (In_sokoban(&u.uz) && !mindless(ptr)) /* know about traps here */ mtmp->mtrapseen = (1L << (PIT - 1)) | (1L << (HOLE - 1)); if (ptr->msound == MS_LEADER) /* leader knows about portal */ - mtmp->mtrapseen |= (1 << (MAGIC_PORTAL-1)); + mtmp->mtrapseen |= (1L << (MAGIC_PORTAL-1)); place_monster(mtmp, x, y); mtmp->mcansee = mtmp->mcanmove = TRUE; @@ -955,7 +959,7 @@ mtmp->cham = CHAM_ORDINARY; else { mtmp->cham = mcham; - (void) newcham(mtmp, rndmonst(), FALSE); + (void) newcham(mtmp, rndmonst(), FALSE, FALSE); } } else if (mndx == PM_WIZARD_OF_YENDOR) { mtmp->iswiz = TRUE; @@ -1346,6 +1350,12 @@ if (mtmp->mhp <= 0) return ((struct permonst *)0); + /* note: none of the monsters with special hit point calculations + have both little and big forms */ + oldtype = monsndx(ptr); + newtype = little_to_big(oldtype); + if (newtype == PM_PRIEST && mtmp->female) newtype = PM_PRIESTESS; + /* growth limits differ depending on method of advancement */ if (victim) { /* killed a monster */ /* @@ -1362,6 +1372,9 @@ else if (is_home_elemental(ptr)) hp_threshold *= 3; lev_limit = 3 * (int)ptr->mlevel / 2; /* same as adj_lev() */ + /* If they can grow up, be sure the level is high enough for that */ + if (oldtype != newtype && mons[newtype].mlevel > lev_limit) + lev_limit = (int)mons[newtype].mlevel; /* number of hit points to gain; unlike for the player, we put the limit at the bottom of the next level rather than the top */ max_increase = rnd((int)victim->m_lev + 1); @@ -1386,11 +1399,6 @@ else if (lev_limit < 5) lev_limit = 5; /* arbitrary */ else if (lev_limit > 49) lev_limit = (ptr->mlevel > 49 ? 50 : 49); - /* note: none of the monsters with special hit point calculations - have both little and big forms */ - oldtype = monsndx(ptr); - newtype = little_to_big(oldtype); - if (newtype == PM_PRIEST && mtmp->female) newtype = PM_PRIESTESS; if ((int)++mtmp->m_lev >= mons[newtype].mlevel && newtype != oldtype) { ptr = &mons[newtype]; if (mvitals[newtype].mvflags & G_GENOD) { /* allow G_EXTINCT */ @@ -1435,7 +1443,7 @@ if (mtmp->data->mlet == S_DEMON) { /* demons never get blessed objects */ if (otmp->blessed) curse(otmp); - } else if(is_lminion(mtmp->data)) { + } else if(is_lminion(mtmp)) { /* lawful minions don't get cursed, bad, or rusting objects */ otmp->cursed = FALSE; if(otmp->spe < 0) otmp->spe = 0; @@ -1597,7 +1605,7 @@ static NEARDATA char syms[] = { MAXOCLASSES, MAXOCLASSES+1, RING_CLASS, WAND_CLASS, WEAPON_CLASS, - FOOD_CLASS, GOLD_CLASS, SCROLL_CLASS, POTION_CLASS, ARMOR_CLASS, + FOOD_CLASS, COIN_CLASS, SCROLL_CLASS, POTION_CLASS, ARMOR_CLASS, AMULET_CLASS, TOOL_CLASS, ROCK_CLASS, GEM_CLASS, SPBOOK_CLASS, S_MIMIC_DEF, S_MIMIC_DEF, S_MIMIC_DEF, }; @@ -1692,7 +1700,7 @@ if (s_sym >= MAXOCLASSES) { ap_type = M_AP_FURNITURE; appear = s_sym == MAXOCLASSES ? S_upstair : S_dnstair; - } else if (s_sym == GOLD_CLASS) { + } else if (s_sym == COIN_CLASS) { ap_type = M_AP_OBJECT; appear = GOLD_PIECE; } else { diff -Naurd ../nethack-3.4.0/src/mapglyph.c ./src/mapglyph.c --- ../nethack-3.4.0/src/mapglyph.c Wed Mar 20 23:43:08 2002 +++ ./src/mapglyph.c Mon Feb 24 15:25:05 2003 @@ -7,6 +7,7 @@ #include "wintty.h" /* for prototype of has_color() only */ #endif #include "color.h" +#define HI_DOMESTIC CLR_WHITE /* monst.c */ int explcolors[] = { CLR_BLACK, /* dark */ @@ -64,7 +65,9 @@ unsigned *ospecial; { register int offset; +#if defined(TEXTCOLOR) || defined(ROGUE_COLOR) int color = NO_COLOR; +#endif uchar ch; unsigned special = 0; @@ -126,7 +129,7 @@ #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) { switch(objects[offset].oc_class) { - case GOLD_CLASS: color = CLR_YELLOW; break; + case COIN_CLASS: color = CLR_YELLOW; break; case FOOD_CLASS: color = CLR_RED; break; default: color = CLR_BRIGHT_BLUE; break; } @@ -194,7 +197,15 @@ color = NO_COLOR; } else #endif + { mon_color(glyph); + /* special case the hero for `showrace' option */ +#ifdef TEXTCOLOR + if (iflags.use_color && x == u.ux && y == u.uy && + iflags.showrace && !Upolyd) + color = HI_DOMESTIC; +#endif + } } #ifdef TEXTCOLOR @@ -210,21 +221,11 @@ # endif color = NO_COLOR; #endif - if (ochar) - *ochar = (int)ch; - else - impossible("glyphmap(): Invalid output character buffer."); - - if (ospecial) - *ospecial = special; - else - impossible("glyphmap(): Invalid special feature return buffer."); + *ochar = (int)ch; + *ospecial = special; #ifdef TEXTCOLOR - if (ocolor) - *ocolor = color; - else - impossible("glyphmap(): Invalid color buffer."); + *ocolor = color; #endif return; } diff -Naurd ../nethack-3.4.0/src/mcastu.c ./src/mcastu.c --- ../nethack-3.4.0/src/mcastu.c Wed Mar 20 23:43:08 2002 +++ ./src/mcastu.c Mon Feb 24 15:25:05 2003 @@ -40,7 +40,7 @@ #ifdef OVL0 -extern const char *flash_types[]; /* from zap.c */ +extern const char * const flash_types[]; /* from zap.c */ /* feedback when frustrated monster couldn't cast a spell */ STATIC_OVL @@ -91,7 +91,7 @@ case 17: case 16: case 15: - return MGC_SUMMON_MONS; /* also aggravates */ + return MGC_SUMMON_MONS; case 14: case 13: return MGC_AGGRAVATION; @@ -181,7 +181,7 @@ * attacking casts spells only a small portion of the time that an * attacking monster does. */ - if (mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) { + if ((mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) && ml) { int cnt = 40; do { @@ -355,7 +355,7 @@ } else impossible("bad wizard cloning?"); break; - case MGC_SUMMON_MONS: /* also aggravates */ + case MGC_SUMMON_MONS: { int count; @@ -542,9 +542,12 @@ boolean success; int i; coord bypos; + int quan; + quan = (mtmp->m_lev < 2) ? 1 : rnd((int)mtmp->m_lev / 2); + if (quan < 3) quan = 3; success = pm ? TRUE : FALSE; - for (i = 0; i <= (int) mtmp->m_lev; i++) { + for (i = 0; i <= quan; i++) { if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data)) break; if ((pm = mkclass(let,0)) != 0 && diff -Naurd ../nethack-3.4.0/src/mhitm.c ./src/mhitm.c --- ../nethack-3.4.0/src/mhitm.c Wed Mar 20 23:43:08 2002 +++ ./src/mhitm.c Mon Feb 24 15:25:05 2003 @@ -242,7 +242,7 @@ magr->weapon_check = NEED_HTH_WEAPON; if (mon_wield_item(magr) != 0) return 0; } - possibly_unwield(magr); + possibly_unwield(magr, FALSE); otmp = MON_WEP(magr); if (otmp) { @@ -306,8 +306,12 @@ break; case AT_EXPL: - strike = 1; /* automatic hit */ res[i] = explmm(magr, mdef, mattk); + if (res[i] == MM_MISS) { /* cancelled--no attack */ + strike = 0; + attk = 0; + } else + strike = 1; /* automatic hit */ break; case AT_ENGL: @@ -537,6 +541,9 @@ { int result; + if (magr->mcan) + return MM_MISS; + if(cansee(magr->mx, magr->my)) pline("%s explodes!", Monnam(magr)); else noises(magr, mattk); @@ -563,19 +570,21 @@ register struct monst *magr, *mdef; register struct attack *mattk; { - struct permonst *pa = magr->data, *pd = mdef->data; - int tmp = d((int)mattk->damn,(int)mattk->damd); struct obj *obj; char buf[BUFSZ]; - int protector = - mattk->aatyp == AT_TENT ? 0 : - mattk->aatyp == AT_KICK ? W_ARMF : W_ARMG; - int num; + struct permonst *pa = magr->data, *pd = mdef->data; + int armpro, num, tmp = d((int)mattk->damn, (int)mattk->damd); + boolean cancelled; - if (touch_petrifies(pd) && !resists_ston(magr) && - (mattk->aatyp != AT_WEAP || !otmp) && - (mattk->aatyp != AT_GAZE && mattk->aatyp != AT_EXPL) && - !(magr->misc_worn_check & protector)) { + if (touch_petrifies(pd) && !resists_ston(magr)) { + long protector = attk_protection((int)mattk->aatyp), + wornitems = magr->misc_worn_check; + + /* wielded weapon gives same protection as gloves here */ + if (otmp != 0) wornitems |= W_ARMG; + + if (protector == 0L || + (protector != ~0L && (wornitems & protector) != protector)) { if (poly_when_stoned(pa)) { mon_to_stone(magr); return MM_HIT; /* no damage during the polymorph */ @@ -586,8 +595,13 @@ else if (magr->mtame && !vis) You(brief_feeling, "peculiarly sad"); return MM_AGR_DIED; + } } + /* cancellation factor is the same as when attacking the hero */ + armpro = magic_negation(mdef); + cancelled = magr->mcan || !((rn2(3) >= armpro) || !rn2(50)); + switch(mattk->adtyp) { case AD_DGST: /* eating a Rider or its corpse is fatal */ @@ -641,18 +655,24 @@ pline("%s %s for a moment.", Monnam(mdef), makeplural(stagger(mdef->data, "stagger"))); mdef->mstun = 1; - /* fall through */ + goto physical; + case AD_LEGS: + if (magr->mcan) { + tmp = 0; + break; + } + goto physical; case AD_WERE: case AD_HEAL: - case AD_LEGS: case AD_PHYS: - if (mattk->aatyp == AT_KICK && thick_skinned(pd)) - tmp = 0; - else if(mattk->aatyp == AT_WEAP) { + physical: + if (mattk->aatyp == AT_KICK && thick_skinned(pd)) { + tmp = 0; + } else if(mattk->aatyp == AT_WEAP) { if(otmp) { if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])) - goto do_stone_goto_label; + goto do_stone; tmp += dmgval(otmp, mdef); if (otmp->oartifact) { (void)artifact_hit(magr,mdef, otmp, &tmp, dieroll); @@ -673,15 +693,13 @@ } break; case AD_FIRE: - if (magr->mcan) { + if (cancelled) { tmp = 0; break; } if (vis) pline("%s is %s!", Monnam(mdef), - mdef->data == &mons[PM_WATER_ELEMENTAL] ? "boiling" : - mattk->aatyp == AT_HUGS ? - "being roasted" : "on fire"); + on_fire(mdef->data, mattk)); if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) { if (vis) pline("%s burns completely!", Monnam(mdef)); @@ -706,7 +724,7 @@ tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE); break; case AD_COLD: - if (magr->mcan) { + if (cancelled) { tmp = 0; break; } @@ -722,7 +740,7 @@ tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD); break; case AD_ELEC: - if (magr->mcan) { + if (cancelled) { tmp = 0; break; } @@ -755,7 +773,8 @@ if (!rn2(6)) erode_obj(MON_WEP(mdef), TRUE, TRUE); break; case AD_RUST: - if (!magr->mcan && pd == &mons[PM_IRON_GOLEM]) { + if (magr->mcan) break; + if (pd == &mons[PM_IRON_GOLEM]) { if (vis) pline("%s falls to pieces!", Monnam(mdef)); mondied(mdef); if (mdef->mhp > 0) return 0; @@ -765,15 +784,19 @@ 0 : MM_AGR_DIED)); } hurtmarmor(mdef, AD_RUST); + mdef->mstrategy &= ~STRAT_WAITFORU; tmp = 0; break; case AD_CORR: + if (magr->mcan) break; hurtmarmor(mdef, AD_CORR); + mdef->mstrategy &= ~STRAT_WAITFORU; tmp = 0; break; case AD_DCAY: - if (!magr->mcan && (pd == &mons[PM_WOOD_GOLEM] || - pd == &mons[PM_LEATHER_GOLEM])) { + if (magr->mcan) break; + if (pd == &mons[PM_WOOD_GOLEM] || + pd == &mons[PM_LEATHER_GOLEM]) { if (vis) pline("%s falls to pieces!", Monnam(mdef)); mondied(mdef); if (mdef->mhp > 0) return 0; @@ -783,12 +806,14 @@ 0 : MM_AGR_DIED)); } hurtmarmor(mdef, AD_DCAY); + mdef->mstrategy &= ~STRAT_WAITFORU; tmp = 0; break; case AD_STON: -do_stone_goto_label: + if (magr->mcan) break; + do_stone: /* may die from the acid if it eats a stone-curing corpse */ - if (munstone(mdef, FALSE)) goto label2; + if (munstone(mdef, FALSE)) goto post_stone; if (poly_when_stoned(pd)) { mon_to_stone(mdef); tmp = 0; @@ -797,7 +822,7 @@ if (!resists_ston(mdef)) { if (vis) pline("%s turns to stone!", Monnam(mdef)); monstone(mdef); -label2: if (mdef->mhp > 0) return 0; + post_stone: if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) You(brief_feeling, "peculiarly sad"); return (MM_DEF_DIED | (grow_up(magr,mdef) ? @@ -806,11 +831,12 @@ tmp = (mattk->adtyp == AD_STON ? 0 : 1); break; case AD_TLPT: - if (!magr->mcan && tmp < mdef->mhp && !tele_restrict(mdef)) { + if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) { char mdef_Monnam[BUFSZ]; /* save the name before monster teleports, otherwise we'll get "it" in the suddenly disappears message */ if (vis) Strcpy(mdef_Monnam, Monnam(mdef)); + mdef->mstrategy &= ~STRAT_WAITFORU; rloc(mdef); if (vis && !canspotmon(mdef) #ifdef STEED @@ -821,30 +847,33 @@ } break; case AD_SLEE: - if (!magr->mcan && !mdef->msleeping && + if (!cancelled && !mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) { if (vis) { Strcpy(buf, Monnam(mdef)); pline("%s is put to sleep by %s.", buf, mon_nam(magr)); } + mdef->mstrategy &= ~STRAT_WAITFORU; slept_monst(mdef); } break; case AD_PLYS: - if(!magr->mcan && mdef->mcanmove) { + if(!cancelled && mdef->mcanmove) { if (vis) { Strcpy(buf, Monnam(mdef)); pline("%s is frozen by %s.", buf, mon_nam(magr)); } mdef->mcanmove = 0; mdef->mfrozen = rnd(10); + mdef->mstrategy &= ~STRAT_WAITFORU; } break; case AD_SLOW: - if (!magr->mcan && vis && mdef->mspeed != MSLOW) { + if (!cancelled && mdef->mspeed != MSLOW) { unsigned int oldspeed = mdef->mspeed; mon_adjust_speed(mdef, -1, (struct obj *)0); + mdef->mstrategy &= ~STRAT_WAITFORU; if (mdef->mspeed != oldspeed && vis) pline("%s slows down.", Monnam(mdef)); } @@ -857,6 +886,7 @@ if (!magr->mcan && !mdef->mconf && !magr->mspec_used) { if (vis) pline("%s looks confused.", Monnam(mdef)); mdef->mconf = 1; + mdef->mstrategy &= ~STRAT_WAITFORU; } break; case AD_BLND: @@ -869,6 +899,7 @@ if ((rnd_tmp += mdef->mblinded) > 127) rnd_tmp = 127; mdef->mblinded = rnd_tmp; mdef->mcansee = 0; + mdef->mstrategy &= ~STRAT_WAITFORU; } tmp = 0; break; @@ -877,6 +908,7 @@ if (vis) pline("%s looks %sconfused.", Monnam(mdef), mdef->mconf ? "more " : ""); mdef->mconf = 1; + mdef->mstrategy &= ~STRAT_WAITFORU; } tmp = 0; break; @@ -884,6 +916,7 @@ if (!night() && (pa == &mons[PM_GREMLIN])) break; if (!magr->mcan && !rn2(10)) { mdef->mcan = 1; /* cancelled regardless of lifesave */ + mdef->mstrategy &= ~STRAT_WAITFORU; if (is_were(pd) && pd->mlet != S_HUMAN) were_change(mdef); if (pd == &mons[PM_CLAY_GOLEM]) { @@ -926,6 +959,7 @@ add_to_minv(magr, gold); } #endif + mdef->mstrategy &= ~STRAT_WAITFORU; if (vis) { Strcpy(buf, Monnam(magr)); pline("%s steals some gold from %s.", buf, mon_nam(mdef)); @@ -937,7 +971,7 @@ } break; case AD_DRLI: - if (rn2(2) && !resists_drli(mdef)) { + if (!cancelled && !rn2(3) && !resists_drli(mdef)) { tmp = d(2,6); if (vis) pline("%s suddenly seems weaker!", Monnam(mdef)); @@ -953,13 +987,13 @@ #endif case AD_SITM: /* for now these are the same */ case AD_SEDU: + if (magr->mcan) break; /* find an object to steal, non-cursed if magr is tame */ - for (obj = mdef->minvent; obj; obj = obj->nobj) { + for (obj = mdef->minvent; obj; obj = obj->nobj) if (!magr->mtame || !obj->cursed) break; - } - if (!magr->mcan && obj) { + if (obj) { char onambuf[BUFSZ], mdefnambuf[BUFSZ]; /* make a special x_monnam() call that never omits @@ -979,7 +1013,7 @@ if (otmp->owornmask & W_WEP) setmnotwielded(mdef,otmp); otmp->owornmask = 0L; - update_mon_intrinsics(mdef, otmp, FALSE); + update_mon_intrinsics(mdef, otmp, FALSE, FALSE); } /* add_to_minv() might free otmp [if it merges] */ if (vis) @@ -990,7 +1024,8 @@ pline("%s steals %s from %s!", buf, onambuf, mdefnambuf); } - possibly_unwield(mdef); + possibly_unwield(mdef, FALSE); + mdef->mstrategy &= ~STRAT_WAITFORU; mselftouch(mdef, (const char *)0, FALSE); if (mdef->mhp <= 0) return (MM_DEF_DIED | (grow_up(magr,mdef) ? @@ -1007,7 +1042,7 @@ case AD_DRST: case AD_DRDX: case AD_DRCO: - if (!magr->mcan && !rn2(8)) { + if (!cancelled && !rn2(8)) { if (vis) pline("%s %s was poisoned!", s_suffix(Monnam(magr)), mpoisons_subj(magr, mattk)); @@ -1055,18 +1090,25 @@ s_suffix(Monnam(mdef))); break; case AD_SLIM: - if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] && - mdef->data != &mons[PM_FIRE_ELEMENTAL] && - mdef->data != &mons[PM_SALAMANDER] && - mdef->data != &mons[PM_GREEN_SLIME]) { - if (vis) pline("%s turns into slime.", Monnam(mdef)); - (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE); - tmp = 0; - } - break; + if (cancelled) break; /* physical damage only */ + if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] && + mdef->data != &mons[PM_FIRE_ELEMENTAL] && + mdef->data != &mons[PM_SALAMANDER] && + mdef->data != &mons[PM_GREEN_SLIME]) { + (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis); + mdef->mstrategy &= ~STRAT_WAITFORU; + tmp = 0; + } + break; case AD_STCK: + if (cancelled) tmp = 0; + break; case AD_WRAP: /* monsters cannot grab one another, it's too hard */ - case AD_ENCH: /* There's no msomearmor() function, so just do damage */ + if (magr->mcan) tmp = 0; + break; + case AD_ENCH: + /* there's no msomearmor() function, so just do damage */ + /* if (cancelled) break; */ break; default: tmp = 0; break; @@ -1082,6 +1124,23 @@ } monkilled(mdef, "", (int)mattk->adtyp); if (mdef->mhp > 0) return 0; /* mdef lifesaved */ + + if (mattk->adtyp == AD_DGST) { + /* various checks similar to dog_eat and meatobj. + * after monkilled() to provide better message ordering */ + if (mdef->cham != CHAM_ORDINARY) { + (void) newcham(magr, (struct permonst *)0, FALSE, TRUE); + } else if (mdef->data == &mons[PM_GREEN_SLIME]) { + (void) newcham(magr, &mons[PM_GREEN_SLIME], FALSE, TRUE); + } else if (mdef->data == &mons[PM_WRAITH]) { + (void) grow_up(magr, (struct monst *)0); + /* don't grow up twice */ + return (MM_DEF_DIED | (magr->mhp > 0 ? 0 : MM_AGR_DIED)); + } else if (mdef->data == &mons[PM_NURSE]) { + magr->mhp = magr->mhpmax; + } + } + return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED)); } return(MM_HIT); @@ -1336,6 +1395,49 @@ return (mdead | mhit); } +/* "aggressive defense"; what type of armor prevents specified attack + from touching its target? */ +long +attk_protection(aatyp) +int aatyp; +{ + long w_mask = 0L; + + switch (aatyp) { + case AT_NONE: + case AT_SPIT: + case AT_EXPL: + case AT_BOOM: + case AT_GAZE: + case AT_BREA: + case AT_MAGC: + w_mask = ~0L; /* special case; no defense needed */ + break; + case AT_CLAW: + case AT_TUCH: + case AT_WEAP: + w_mask = W_ARMG; /* caller needs to check for weapon */ + break; + case AT_KICK: + w_mask = W_ARMF; + break; + case AT_BUTT: + w_mask = W_ARMH; + break; + case AT_HUGS: + w_mask = (W_ARMC|W_ARMG); /* attacker needs both to be protected */ + break; + case AT_BITE: + case AT_STNG: + case AT_ENGL: + case AT_TENT: + default: + w_mask = 0L; /* no defense available */ + break; + } + return w_mask; +} + #endif /* OVLB */ /*mhitm.c*/ diff -Naurd ../nethack-3.4.0/src/mhitu.c ./src/mhitu.c --- ../nethack-3.4.0/src/mhitu.c Wed Mar 20 23:43:08 2002 +++ ./src/mhitu.c Mon Feb 24 15:25:05 2003 @@ -316,7 +316,7 @@ /* Might be attacking your image around the corner, or * invisible, or you might be blind.... */ - + if(!ranged) nomul(0); if(mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data))) return(0); @@ -356,6 +356,7 @@ u.uundetected = 0; if (is_hider(youmonst.data)) { coord cc; /* maybe we need a unexto() function? */ + struct obj *obj; You("fall from the %s!", ceiling(u.ux,u.uy)); if (enexto(&cc, u.ux, u.uy, youmonst.data)) { @@ -363,7 +364,7 @@ newsym(mtmp->mx,mtmp->my); place_monster(mtmp, u.ux, u.uy); if(mtmp->wormno) worm_move(mtmp); - teleds(cc.x, cc.y); + teleds(cc.x, cc.y, TRUE); set_apparxy(mtmp); newsym(u.ux,u.uy); } else { @@ -377,7 +378,8 @@ if (youmonst.data->mlet != S_PIERCER) return(0); /* trappers don't attack */ - if (which_armor(mtmp, WORN_HELMET)) { + obj = which_armor(mtmp, WORN_HELMET); + if (obj && is_metallic(obj)) { Your("blow glances off %s helmet.", s_suffix(mon_nam(mtmp))); } else { @@ -436,15 +438,15 @@ return(0); } - /* player might be mimicking gold */ - if (youmonst.m_ap_type == M_AP_OBJECT - && youmonst.mappearance == GOLD_PIECE - && !range2 && foundyou && !u.uswallow) { + /* player might be mimicking an object */ + if (youmonst.m_ap_type == M_AP_OBJECT && !range2 && foundyou && !u.uswallow) { if (!youseeit) - pline("%s %s!", Something, likes_gold(mtmp->data) ? + pline("%s %s!", Something, + (likes_gold(mtmp->data) && youmonst.mappearance == GOLD_PIECE) ? "tries to pick you up" : "disturbs you"); - else pline("Wait, %s! That gold is really %s named %s!", + else pline("Wait, %s! That %s is really %s named %s!", m_monnam(mtmp), + mimic_obj_name(&youmonst), an(mons[u.umonnum].mname), plname); if (multi < 0) { /* this should always be the case */ @@ -452,7 +454,7 @@ Sprintf(buf, "You appear to be %s again.", Upolyd ? (const char *) an(youmonst.data->mname) : (const char *) "yourself"); - unmul(buf); /* immediately stop mimicking gold */ + unmul(buf); /* immediately stop mimicking */ } return 0; } @@ -477,7 +479,7 @@ && mtmp->data != &mons[PM_BALROG] && mtmp->data != &mons[PM_SUCCUBUS] && mtmp->data != &mons[PM_INCUBUS]) - if(!mtmp->mcan && !rn2(13)) msummon(mdat); + if(!mtmp->mcan && !rn2(13)) msummon(mtmp); /* Special lycanthrope handling code */ if(!mtmp->cham && is_were(mdat) && !range2) { @@ -787,6 +789,51 @@ return FALSE; } +/* armor that sufficiently covers the body might be able to block magic */ +int +magic_negation(mon) +struct monst *mon; +{ + struct obj *armor; + int armpro = 0; + + armor = (mon == &youmonst) ? uarm : which_armor(mon, W_ARM); + if (armor && armpro < objects[armor->otyp].a_can) + armpro = objects[armor->otyp].a_can; + armor = (mon == &youmonst) ? uarmc : which_armor(mon, W_ARMC); + if (armor && armpro < objects[armor->otyp].a_can) + armpro = objects[armor->otyp].a_can; + armor = (mon == &youmonst) ? uarmh : which_armor(mon, W_ARMH); + if (armor && armpro < objects[armor->otyp].a_can) + armpro = objects[armor->otyp].a_can; + + /* armor types for shirt, gloves, shoes, and shield don't currently + provide any magic cancellation but we might as well be complete */ +#ifdef TOURIST + armor = (mon == &youmonst) ? uarmu : which_armor(mon, W_ARMU); + if (armor && armpro < objects[armor->otyp].a_can) + armpro = objects[armor->otyp].a_can; +#endif + armor = (mon == &youmonst) ? uarmg : which_armor(mon, W_ARMG); + if (armor && armpro < objects[armor->otyp].a_can) + armpro = objects[armor->otyp].a_can; + armor = (mon == &youmonst) ? uarmf : which_armor(mon, W_ARMF); + if (armor && armpro < objects[armor->otyp].a_can) + armpro = objects[armor->otyp].a_can; + armor = (mon == &youmonst) ? uarms : which_armor(mon, W_ARMS); + if (armor && armpro < objects[armor->otyp].a_can) + armpro = objects[armor->otyp].a_can; + +#ifdef STEED + /* this one is really a stretch... */ + armor = (mon == &youmonst) ? 0 : which_armor(mon, W_SADDLE); + if (armor && armpro < objects[armor->otyp].a_can) + armpro = objects[armor->otyp].a_can; +#endif + + return armpro; +} + /* * hitmu: monster hits you * returns 2 if monster dies (e.g. "yellow light"), 1 otherwise @@ -840,13 +887,7 @@ /* Use uncancelled when the cancellation factor takes into account certain * armor's special magic protection. Otherwise just use !mtmp->mcan. */ - armpro = 0; - if (uarm && armpro < objects[uarm->otyp].a_can) - armpro = objects[uarm->otyp].a_can; - if (uarmc && armpro < objects[uarmc->otyp].a_can) - armpro = objects[uarmc->otyp].a_can; - if (uarmh && armpro < objects[uarmh->otyp].a_can) - armpro = objects[uarmh->otyp].a_can; + armpro = magic_negation(&youmonst); uncancelled = !mtmp->mcan && ((rn2(3) >= armpro) || !rn2(50)); permdmg = 0; @@ -912,11 +953,7 @@ case AD_FIRE: hitmsg(mtmp, mattk); if (uncancelled) { - pline("You're %s!", - youmonst.data == &mons[PM_WATER_ELEMENTAL] ? - "boiling" : - mattk->aatyp == AT_HUGS ? "being roasted" : - "on fire"); + pline("You're %s!", on_fire(youmonst.data, mattk)); if (youmonst.data == &mons[PM_STRAW_GOLEM] || youmonst.data == &mons[PM_PAPER_GOLEM]) { You("roast!"); @@ -990,12 +1027,9 @@ dopois: hitmsg(mtmp, mattk); if (uncancelled && !rn2(8)) { - Sprintf(buf, "%s %s", - !canspotmon(mtmp) ? "Its" : - Hallucination ? s_suffix(rndmonnam()) : - s_suffix(mdat->mname), - mpoisons_subj(mtmp, mattk)); - poisoned(buf, ptmp, mdat->mname, 30); + Sprintf(buf, "%s %s", + s_suffix(Monnam(mtmp)), mpoisons_subj(mtmp, mattk)); + poisoned(buf, ptmp, mdat->mname, 30); } break; case AD_DRIN: @@ -1058,14 +1092,15 @@ case AD_PLYS: hitmsg(mtmp, mattk); if (uncancelled && multi >= 0 && !rn2(3)) { - if (Free_action) You("momentarily stiffen."); - else { - if (Blind) You("are frozen!"); - else You("are frozen by %s!", mon_nam(mtmp)); - nomovemsg = 0; /* default: "you can move again" */ - nomul(-rnd(10)); - exercise(A_DEX, FALSE); - } + if (Free_action) { + You("momentarily stiffen."); + } else { + if (Blind) You("are frozen!"); + else You("are frozen by %s!", mon_nam(mtmp)); + nomovemsg = 0; /* default: "you can move again" */ + nomul(-rnd(10)); + exercise(A_DEX, FALSE); + } } break; case AD_DRLI: @@ -1081,6 +1116,7 @@ /* This case is too obvious to ignore, but Nethack is not in * general very good at considering height--most short monsters * still _can_ attack you when you're flying or mounted. + * [FIXME: why can't a flying attacker overcome this?] */ if ( #ifdef STEED @@ -1089,9 +1125,11 @@ Levitation || Flying) { pline("%s tries to reach your %s %s!", Monnam(mtmp), sidestr, body_part(LEG)); + dmg = 0; } else if (mtmp->mcan) { pline("%s nuzzles against your %s %s!", Monnam(mtmp), sidestr, body_part(LEG)); + dmg = 0; } else { if (uarmf) { if (rn2(2) && (uarmf->otyp == LOW_BOOTS || @@ -1104,6 +1142,7 @@ else { pline("%s scratches your %s boot!", Monnam(mtmp), sidestr); + dmg = 0; break; } } else pline("%s pricks your %s %s!", Monnam(mtmp), @@ -1125,7 +1164,7 @@ You_hear("%s hissing!", s_suffix(mon_nam(mtmp))); if(!rn2(10) || (flags.moonphase == NEW_MOON && !have_lizard())) { -do_stone: + do_stone: if (!Stoned && !Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { @@ -1158,8 +1197,9 @@ } else if(u.ustuck == mtmp) { if (is_pool(mtmp->mx,mtmp->my) && !Swimming && !Amphibious) { - boolean moat = (levl[u.ux][u.uy].typ != POOL) && - (levl[u.ux][u.uy].typ != WATER) && + boolean moat = + (levl[mtmp->mx][mtmp->my].typ != POOL) && + (levl[mtmp->mx][mtmp->my].typ != WATER) && !Is_medusa_level(&u.uz) && !Is_waterlevel(&u.uz); @@ -1235,11 +1275,6 @@ if (!is_animal(mtmp->data) && !tele_restrict(mtmp)) rloc(mtmp); if (is_animal(mtmp->data) && *buf) { - /* set mavenge bit for animals so knights won't - suffer an alignment penalty during retaliation; - note that only happens when the thief succeeds - in getting something (*buf != 0) */ - mtmp->mavenge = 1; if (canseemon(mtmp)) pline("%s tries to %s away with %s.", Monnam(mtmp), @@ -1304,6 +1339,11 @@ hurtarmor(AD_DCAY); break; case AD_HEAL: + /* a cancelled nurse is just an ordinary monster */ + if (mtmp->mcan) { + hitmsg(mtmp, mattk); + break; + } if(!uwep #ifdef TOURIST && !uarmu @@ -1596,7 +1636,7 @@ i = number_leashed(); if (i > 0) { - char *s = (i > 1) ? "leashes" : "leash"; + const char *s = (i > 1) ? "leashes" : "leash"; pline_The("%s %s loose.", s, vtense(s, "snap")); unleash_all(); } @@ -2350,7 +2390,7 @@ /* obj == uarmh */ hairbuf); } - remove_worn_item(obj); + remove_worn_item(obj, TRUE); } #endif /* SEDUCE */ @@ -2394,15 +2434,16 @@ goto assess_dmg; case AD_STON: /* cockatrice */ { - int protector = - mattk->aatyp == AT_TENT ? 0 : - mattk->aatyp == AT_KICK ? W_ARMF : W_ARMG; - if (!resists_ston(mtmp) && - (mattk->aatyp != AT_WEAP || !MON_WEP(mtmp)) && - mattk->aatyp != AT_GAZE && mattk->aatyp != AT_EXPL && - mattk->aatyp != AT_MAGC && - !(mtmp->misc_worn_check & protector)) { - if(poly_when_stoned(mtmp->data)) { + long protector = attk_protection((int)mattk->aatyp), + wornitems = mtmp->misc_worn_check; + + /* wielded weapon gives same protection as gloves here */ + if (MON_WEP(mtmp) != 0) wornitems |= W_ARMG; + + if (!resists_ston(mtmp) && (protector == 0L || + (protector != ~0L && + (wornitems & protector) != protector))) { + if (poly_when_stoned(mtmp->data)) { mon_to_stone(mtmp); return (1); } diff -Naurd ../nethack-3.4.0/src/minion.c ./src/minion.c --- ../nethack-3.4.0/src/minion.c Wed Mar 20 23:43:09 2002 +++ ./src/minion.c Mon Feb 24 15:25:05 2003 @@ -7,12 +7,25 @@ #include "epri.h" void -msummon(ptr) /* ptr summons a monster */ -register struct permonst *ptr; +msummon(mon) /* mon summons a monster */ +struct monst *mon; { + register struct permonst *ptr; register int dtype = NON_PM, cnt = 0; - aligntyp atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp); + aligntyp atyp; + struct monst *mtmp; + if (mon) { + ptr = mon->data; + atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp); + if (mon->ispriest || mon->data == &mons[PM_ALIGNED_PRIEST] + || mon->data == &mons[PM_ANGEL]) + atyp = EPRI(mon)->shralign; + } else { + ptr = &mons[PM_WIZARD_OF_YENDOR]; + atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp); + } + if (is_dprince(ptr) || (ptr == &mons[PM_WIZARD_OF_YENDOR])) { dtype = (!rn2(20)) ? dprince(atyp) : (!rn2(4)) ? dlord(atyp) : ndemon(atyp); @@ -25,10 +38,26 @@ dtype = (!rn2(20)) ? dlord(atyp) : (!rn2(6)) ? ndemon(atyp) : monsndx(ptr); cnt = 1; - } else if (is_lminion(ptr)) { + } else if (is_lminion(mon)) { dtype = (is_lord(ptr) && !rn2(20)) ? llord() : (is_lord(ptr) || !rn2(6)) ? lminion() : monsndx(ptr); cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1; + } else if (ptr == &mons[PM_ANGEL]) { + /* non-lawful angels can also summon */ + if (!rn2(6)) { + switch (atyp) { /* see summon_minion */ + case A_NEUTRAL: + dtype = PM_AIR_ELEMENTAL + rn2(4); + break; + case A_CHAOTIC: + case A_NONE: + dtype = ndemon(atyp); + break; + } + } else { + dtype = PM_ANGEL; + } + cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1; } if (dtype == NON_PM) return; @@ -45,10 +74,13 @@ } while (cnt > 0) { - (void)makemon(&mons[dtype], u.ux, u.uy, NO_MM_FLAGS); + mtmp = makemon(&mons[dtype], u.ux, u.uy, NO_MM_FLAGS); + if (mtmp && (dtype == PM_ANGEL)) { + /* alignment should match the summoner */ + EPRI(mtmp)->shralign = atyp; + } cnt--; } - return; } void @@ -110,11 +142,12 @@ demon_talk(mtmp) /* returns 1 if it won't attack. */ register struct monst *mtmp; { - long demand, offer; + long cash, demand, offer; if (uwep && uwep->oartifact == ART_EXCALIBUR) { pline("%s looks very angry.", Amonnam(mtmp)); mtmp->mpeaceful = mtmp->mtame = 0; + set_malign(mtmp); newsym(mtmp->mx, mtmp->my); return 0; } @@ -132,28 +165,38 @@ return(1); } #ifndef GOLDOBJ - demand = (u.ugold * (rnd(80) + 20 * Athome)) / + cash = u.ugold; #else - demand = (money_cnt(invent) * (rnd(80) + 20 * Athome)) / + cash = money_cnt(invent); #endif + demand = (cash * (rnd(80) + 20 * Athome)) / (100 * (1 + (sgn(u.ualign.type) == sgn(mtmp->data->maligntyp)))); - if (!demand) /* you have no gold */ - return mtmp->mpeaceful = 0; - else { + + if (!demand) { /* you have no gold */ + mtmp->mpeaceful = 0; + set_malign(mtmp); + return 0; + } else { + /* make sure that the demand is unmeetable if the monster + has the Amulet, preventing monster from being satisified + and removed from the game (along with said Amulet...) */ + if (mon_has_amulet(mtmp)) + demand = cash + (long)rn1(1000,40); + pline("%s demands %ld %s for safe passage.", Amonnam(mtmp), demand, currency(demand)); if ((offer = bribe(mtmp)) >= demand) { pline("%s vanishes, laughing about cowardly mortals.", Amonnam(mtmp)); + } else if (offer > 0L && (long)rnd(40) > (demand - offer)) { + pline("%s scowls at you menacingly, then vanishes.", + Amonnam(mtmp)); } else { - if ((long)rnd(40) > (demand - offer)) { - pline("%s scowls at you menacingly, then vanishes.", - Amonnam(mtmp)); - } else { - pline("%s gets angry...", Amonnam(mtmp)); - return mtmp->mpeaceful = 0; - } + pline("%s gets angry...", Amonnam(mtmp)); + mtmp->mpeaceful = 0; + set_malign(mtmp); + return 0; } } mongone(mtmp); diff -Naurd ../nethack-3.4.0/src/mklev.c ./src/mklev.c --- ../nethack-3.4.0/src/mklev.c Wed Mar 20 23:43:09 2002 +++ ./src/mklev.c Mon Feb 24 15:25:05 2003 @@ -35,7 +35,7 @@ STATIC_DCL void FDECL(makeniche,(int)); STATIC_DCL void NDECL(make_niches); -STATIC_PTR int FDECL(do_comp,(const genericptr,const genericptr)); +STATIC_PTR int FDECL( CFDECLSPEC do_comp,(const genericptr,const genericptr)); STATIC_DCL void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int)); STATIC_DCL void FDECL(join,(int,int,BOOLEAN_P)); @@ -55,7 +55,7 @@ /* Args must be (const genericptr) so that qsort will always be happy. */ -STATIC_PTR int +STATIC_PTR int CFDECLSPEC do_comp(vx,vy) const genericptr vx; const genericptr vy; diff -Naurd ../nethack-3.4.0/src/mkmaze.c ./src/mkmaze.c --- ../nethack-3.4.0/src/mkmaze.c Wed Mar 20 23:43:09 2002 +++ ./src/mkmaze.c Mon Feb 24 15:25:05 2003 @@ -288,13 +288,18 @@ boolean oneshot; d_level *lev; { - if (bad_location(x, y, nlx, nly, nhx, nhy)) return FALSE; - if (oneshot) { - /* must make due with the only location possible */ - /* avoid failure due to a misplaced trap */ - /* it might still fail if there's a dungeon feature here */ - struct trap *t = t_at(x,y); - if (t) deltrap(t); + if (bad_location(x, y, nlx, nly, nhx, nhy)) { + if (!oneshot) { + return FALSE; /* caller should try again */ + } else { + /* Must make do with the only location possible; + avoid failure due to a misplaced trap. + It might still fail if there's a dungeon feature here. */ + struct trap *t = t_at(x,y); + + if (t && t->ttyp != MAGIC_PORTAL) deltrap(t); + if (bad_location(x, y, nlx, nly, nhx, nhy)) return FALSE; + } } switch (rtype) { case LR_TELE: @@ -412,7 +417,7 @@ croom = &rooms[0]; /* only one room on the medusa level */ for (tryct = rnd(4); tryct; tryct--) { x = somex(croom); y = somey(croom); - if (goodpos(x, y, (struct monst *)0)) { + if (goodpos(x, y, (struct monst *)0, 0)) { otmp = mk_tt_object(STATUE, x, y); while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) || pm_resistance(&mons[otmp->corpsenm],MR_STONE))) { diff -Naurd ../nethack-3.4.0/src/mkobj.c ./src/mkobj.c --- ../nethack-3.4.0/src/mkobj.c Wed Mar 20 23:43:10 2002 +++ ./src/mkobj.c Mon Feb 24 15:25:05 2003 @@ -1,9 +1,8 @@ -/* SCCS Id: @(#)mkobj.c 3.4 2001/12/03 */ +/* SCCS Id: @(#)mkobj.c 3.4 2002/10/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" -#include "artifact.h" #include "prop.h" STATIC_DCL void FDECL(mkbox_cnts,(struct obj *)); @@ -17,6 +16,8 @@ #endif #endif /* OVL1 */ +extern struct obj *thrownobj; /* defined in dothrow.c */ + /*#define DEBUG_EFFECTS*/ /* show some messages for debugging */ struct icp { @@ -46,7 +47,7 @@ {18, POTION_CLASS}, {18, SCROLL_CLASS}, {12, SPBOOK_CLASS}, -{ 7, GOLD_CLASS}, +{ 7, COIN_CLASS}, { 6, WAND_CLASS}, { 5, RING_CLASS}, { 1, AMULET_CLASS} @@ -175,7 +176,7 @@ if (!(otmp = mkobj(iprobs->iclass, TRUE))) continue; /* handle a couple of special cases */ - if (otmp->oclass == GOLD_CLASS) { + if (otmp->oclass == COIN_CLASS) { /* 2.5 x level's usual amount; weight adjusted below */ otmp->quan = (long)(rnd(level_difficulty()+2) * rnd(75)); otmp->owt = weight(otmp); @@ -609,7 +610,7 @@ mkobj(SPBOOK_CLASS,FALSE)); } break; - case GOLD_CLASS: + case COIN_CLASS: break; /* do nothing */ default: impossible("impossible mkobj %d, sym '%c'.", otmp->otyp, @@ -679,10 +680,12 @@ bless(otmp) register struct obj *otmp; { +#ifdef GOLDOBJ + if (otmp->oclass == COIN_CLASS) return; +#endif otmp->cursed = 0; otmp->blessed = 1; - if (otmp->otyp == LUCKSTONE - || (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) + if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); @@ -696,8 +699,7 @@ register struct obj *otmp; { otmp->blessed = 0; - if (otmp->otyp == LUCKSTONE - || (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) + if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); @@ -707,20 +709,29 @@ curse(otmp) register struct obj *otmp; { +#ifdef GOLDOBJ + if (otmp->oclass == COIN_CLASS) return; +#endif otmp->blessed = 0; otmp->cursed = 1; - if (otmp->otyp == LUCKSTONE - || (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) + /* welded two-handed weapon interferes with some armor removal */ + if (otmp == uwep && bimanual(uwep)) reset_remarm(); + /* rules at top of wield.c state that twoweapon cannot be done + with cursed alternate weapon */ + if (otmp == uswapwep && u.twoweap) + drop_uswapwep(); + /* some cursed items need immediate updating */ + if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); else if (otmp->otyp == FIGURINE) { if (otmp->corpsenm != NON_PM - && !dead_species(otmp->corpsenm,TRUE) + && !dead_species(otmp->corpsenm,TRUE) && (carried(otmp) || mcarried(otmp))) attach_fig_transform_timeout(otmp); } - return; + return; } void @@ -728,13 +739,12 @@ register struct obj *otmp; { otmp->cursed = 0; - if (otmp->otyp == LUCKSTONE - || (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) + if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) - otmp->owt = weight(otmp); + otmp->owt = weight(otmp); else if (otmp->otyp == FIGURINE && otmp->timed) - (void) stop_timer(FIG_TRANSFORM, (genericptr_t) otmp); + (void) stop_timer(FIG_TRANSFORM, (genericptr_t) otmp); return; } @@ -830,7 +840,7 @@ return wt; } else if (obj->oclass == FOOD_CLASS && obj->oeaten) { return eaten_stat((int)obj->quan * wt, obj); - } else if (obj->oclass == GOLD_CLASS) + } else if (obj->oclass == COIN_CLASS) return (int)((obj->quan + 50L) / 100L); else if (obj->otyp == HEAVY_IRON_BALL && obj->owt != 0) return((int)(obj->owt)); /* kludge for "very" heavy iron ball */ @@ -1475,6 +1485,8 @@ if (obj_sheds_light(obj)) del_light_source(LS_OBJECT, (genericptr_t) obj); + if (obj == thrownobj) thrownobj = (struct obj*)0; + free((genericptr_t) obj); } diff -Naurd ../nethack-3.4.0/src/mon.c ./src/mon.c --- ../nethack-3.4.0/src/mon.c Wed Mar 20 23:43:10 2002 +++ ./src/mon.c Mon Feb 24 15:25:05 2003 @@ -254,6 +254,16 @@ if (mtmp->mnamelth) obj = oname(obj, NAME(mtmp)); + /* Avoid "It was hidden under a green mold corpse!" + * during Blind combat. An unseen monster referred to as "it" + * could be killed and leave a corpse. If a hider then hid + * underneath it, you could be told the corpse type of a + * monster that you never knew was there without this. + * The code in hitmu() substitutes the word "something" + * if the corpses obj->dknown is 0. + */ + if (Blind && !sensemon(mtmp)) obj->dknown = 0; + #ifdef INVISIBLE_OBJECTS /* Invisible monster ==> invisible corpse */ obj->oinvis = mtmp->minvis; @@ -276,7 +286,7 @@ if(!Blind && uwep && (warnlevel > lastwarnlev || moves > lastwarntime + warnDelay)) { Your("%s %s!", aobjnam(uwep, "glow"), - hcolor(light_blue)); + hcolor(NH_LIGHT_BLUE)); lastwarnlev = warnlevel; lastwarntime = moves; } @@ -370,7 +380,9 @@ if (!is_clinger(mtmp->data) && !likes_lava(mtmp->data)) { if (!resists_fire(mtmp)) { if (cansee(mtmp->mx,mtmp->my)) - pline("%s burns to a crisp.", Monnam(mtmp)); + pline("%s %s.", Monnam(mtmp), + mtmp->data == &mons[PM_WATER_ELEMENTAL] ? + "boils away" : "burns to a crisp"); mondead(mtmp); } else { @@ -400,6 +412,12 @@ if (cansee(mtmp->mx,mtmp->my)) { pline("%s drowns.", Monnam(mtmp)); } + if (u.ustuck && u.uswallow && u.ustuck == mtmp) { + /* This can happen after a purple worm plucks you off a + flying steed while you are over water. */ + pline("%s sinks as water rushes in and flushes you out.", + Monnam(mtmp)); + } mondead(mtmp); if (mtmp->mhp > 0) { rloc(mtmp); @@ -457,12 +475,19 @@ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; + /* must check non-moving monsters once/turn in case + * they managed to end up in liquid */ + if (mtmp->data->mmove == 0) { + if (vision_full_recalc) vision_recalc(0); + if (minliquid(mtmp)) continue; + } + /* regenerate hit points */ mon_regen(mtmp, FALSE); /* possibly polymorph shapechangers and lycanthropes */ if (mtmp->cham && !rn2(6)) - (void) newcham(mtmp, (struct permonst *)0, FALSE); + (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); were_change(mtmp); /* gradually time out temporary problems */ @@ -642,7 +667,8 @@ delobj(otmp); ptr = mtmp->data; if (poly) { - if (newcham(mtmp, (struct permonst *)0, FALSE)) + if (newcham(mtmp, (struct permonst *)0, + FALSE, FALSE)) ptr = mtmp->data; } else if (grow) { ptr = grow_up(mtmp, (struct monst *)0); @@ -727,7 +753,8 @@ delobj(otmp); /* munch */ ptr = mtmp->data; if (poly) { - if (newcham(mtmp, (struct permonst *)0, FALSE)) ptr = mtmp->data; + if (newcham(mtmp, (struct permonst *)0, FALSE, FALSE)) + ptr = mtmp->data; } else if (grow) { ptr = grow_up(mtmp, (struct monst *)0); } else if (heal) { @@ -766,21 +793,21 @@ register struct monst *mtmp; { register struct obj *gold; + int mat_idx; if ((gold = g_at(mtmp->mx, mtmp->my)) != 0) { + mat_idx = objects[gold->otyp].oc_material; #ifndef GOLDOBJ mtmp->mgold += gold->quan; delobj(gold); - if (cansee(mtmp->mx, mtmp->my) ) { - if (flags.verbose && !mtmp->isgd) - pline("%s picks up some gold.", Monnam(mtmp)); #else obj_extract_self(gold); add_to_minv(mtmp, gold); +#endif if (cansee(mtmp->mx, mtmp->my) ) { if (flags.verbose && !mtmp->isgd) - pline("%s picks up some money.", Monnam(mtmp)); -#endif + pline("%s picks up some %s.", Monnam(mtmp), + mat_idx == GOLD ? "gold" : "money"); newsym(mtmp->mx, mtmp->my); } } @@ -934,6 +961,7 @@ register uchar ntyp; uchar nowtyp; boolean wantpool,poolok,lavaok,nodiag; + boolean rockok = FALSE, treeok = FALSE, thrudoor; int maxx, maxy; x = mon->mx; @@ -945,6 +973,27 @@ poolok = is_flyer(mdat) || is_clinger(mdat) || (is_swimmer(mdat) && !wantpool); lavaok = is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat); + thrudoor = ((flag & (ALLOW_WALL|BUSTDOOR)) != 0L); + if (flag & ALLOW_DIG) { + struct obj *mw_tmp; + + /* need to be specific about what can currently be dug */ + if (!needspick(mdat)) { + rockok = treeok = TRUE; + } else if ((mw_tmp = MON_WEP(mon)) && mw_tmp->cursed && + mon->weapon_check == NO_WEAPON_WANTED) { + rockok = is_pick(mw_tmp); + treeok = is_axe(mw_tmp); + } else { + rockok = (m_carrying(mon, PICK_AXE) || + (m_carrying(mon, DWARVISH_MATTOCK) && + !which_armor(mon, W_ARMS))); + treeok = (m_carrying(mon, AXE) || + (m_carrying(mon, BATTLE_AXE) && + !which_armor(mon, W_ARMS))); + } + thrudoor |= rockok || treeok; + } nexttry: /* eels prefer the water, but if there is no water nearby, they will crawl over land */ @@ -961,14 +1010,13 @@ if(nx == x && ny == y) continue; if(IS_ROCK(ntyp = levl[nx][ny].typ) && !((flag & ALLOW_WALL) && may_passwall(nx,ny)) && - !((flag & ALLOW_DIG) && may_dig(nx,ny))) continue; + !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx,ny))) continue; /* KMH -- Added iron bars */ - if (ntyp == IRONBARS && - !((flag & ALLOW_WALL) && may_passwall(nx,ny))) continue; + if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue; if(IS_DOOR(ntyp) && !amorphous(mdat) && ((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) || - (levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR)) - ) && !(flag & (ALLOW_WALL|ALLOW_DIG|BUSTDOOR))) continue; + (levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))) && + !thrudoor) continue; if(nx != x && ny != y && (nodiag || #ifdef REINCARNATION ((IS_DOOR(nowtyp) && @@ -1288,21 +1336,17 @@ pline("%s medallion begins to glow!", s_suffix(Monnam(mtmp))); makeknown(AMULET_OF_LIFE_SAVING); - pline("%s looks much better!", Monnam(mtmp)); + if (attacktype(mtmp->data, AT_EXPL) + || attacktype(mtmp->data, AT_BOOM)) + pline("%s reconstitutes!", Monnam(mtmp)); + else + pline("%s looks much better!", Monnam(mtmp)); pline_The("medallion crumbles to dust!"); } m_useup(mtmp, lifesave); mtmp->mcanmove = 1; mtmp->mfrozen = 0; if (mtmp->mtame && !mtmp->isminion) { - struct edog *edog = EDOG(mtmp); - if (edog->hungrytime < moves+500) - edog->hungrytime = moves+500; - if (edog->mhpmax_penalty) { - /* was starving */ - mtmp->mhpmax += edog->mhpmax_penalty; - edog->mhpmax_penalty = 0; - } wary_dog(mtmp, FALSE); } if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; @@ -1419,13 +1463,13 @@ else if(mdat->mattk[i].damd) tmp = d((int)mdat->mlevel+1, (int)mdat->mattk[i].damd); else tmp = 0; - if (Half_physical_damage) tmp = (tmp+1) / 2; if (was_swallowed && magr) { if (magr == &youmonst) { There("is an explosion in your %s!", body_part(STOMACH)); Sprintf(killer_buf, "%s explosion", s_suffix(mdat->mname)); + if (Half_physical_damage) tmp = (tmp+1) / 2; losehp(tmp, killer_buf, KILLED_BY_AN); } else { if (flags.soundok) You_hear("an explosion."); @@ -1473,7 +1517,8 @@ mondead(mdef); if (mdef->mhp > 0) return; /* lifesaved */ - if (corpse_chance(mdef, (struct monst *)0, FALSE)) + if (corpse_chance(mdef, (struct monst *)0, FALSE) && + (accessible(mdef->mx, mdef->my) || is_pool(mdef->mx, mdef->my))) (void) make_corpse(mdef); } @@ -1500,7 +1545,7 @@ monstone(mdef) register struct monst *mdef; { - struct obj *otmp, *obj; + struct obj *otmp, *obj, *oldminvent; xchar x = mdef->mx, y = mdef->my; boolean wasinside = FALSE; @@ -1515,12 +1560,12 @@ if ((int)mdef->data->msize > MZ_TINY || !rn2(2 + ((int) (mdef->data->geno & G_FREQ) > 2))) { - otmp = mkcorpstat(STATUE, KEEPTRAITS(mdef) ? mdef : 0, - mdef->data, x, y, FALSE); - if (mdef->mnamelth) otmp = oname(otmp, NAME(mdef)); + oldminvent = 0; /* some objects may end up outside the statue */ while ((obj = mdef->minvent) != 0) { obj_extract_self(obj); + if (obj->owornmask) + update_mon_intrinsics(mdef, obj, FALSE, TRUE); obj_no_longer_held(obj); if (obj->owornmask & W_WEP) setmnotwielded(mdef,obj); @@ -1534,9 +1579,20 @@ place_object(obj, x, y); } else { if (obj->lamplit) end_burn(obj, TRUE); - (void) add_to_container(otmp, obj); + obj->nobj = oldminvent; + oldminvent = obj; } } + /* defer statue creation until after inventory removal + so that saved monster traits won't retain any stale + item-conferred attributes */ + otmp = mkcorpstat(STATUE, KEEPTRAITS(mdef) ? mdef : 0, + mdef->data, x, y, FALSE); + if (mdef->mnamelth) otmp = oname(otmp, NAME(mdef)); + while ((obj = oldminvent) != 0) { + oldminvent = obj->nobj; + (void) add_to_container(otmp, obj); + } #ifndef GOLDOBJ if (mdef->mgold) { struct obj *au; @@ -1707,8 +1763,9 @@ redisp = TRUE; } #endif - if(!accessible(x, y) && !is_pool(x, y)) { - /* might be mimic in wall or corpse in lava */ + if((!accessible(x, y) && !is_pool(x, y)) || + (x == u.ux && y == u.uy)) { + /* might be mimic in wall or corpse in lava or on player's spot */ redisp = TRUE; if(wasinside) spoteffects(TRUE); } else if(x != u.ux || y != u.uy) { @@ -1803,7 +1860,7 @@ /* it's a golem, and not a stone golem */ if(canseemon(mtmp)) pline("%s solidifies...", Monnam(mtmp)); - if (newcham(mtmp, &mons[PM_STONE_GOLEM], FALSE)) { + if (newcham(mtmp, &mons[PM_STONE_GOLEM], FALSE, FALSE)) { if(canseemon(mtmp)) pline("Now it's %s.", an(mtmp->data->mname)); } else { @@ -1862,7 +1919,7 @@ newx = x; newy = y; - if (!goodpos(newx, newy, mtmp)) { + if (!goodpos(newx, newy, mtmp, 0)) { /* actually we have real problems if enexto ever fails. * migrating_mons that need to be placed will cause * no end of trouble. @@ -2025,6 +2082,10 @@ mtmp->meating = 0; /* assume there's no salvagable food left */ setmangry(mtmp); if(mtmp->m_ap_type) seemimic(mtmp); + else if (flags.forcefight && !flags.mon_moving && mtmp->mundetected) { + mtmp->mundetected = 0; + newsym(mtmp->mx, mtmp->my); + } } /* Wake up nearby monsters. */ @@ -2061,16 +2122,21 @@ seemimic(mtmp) register struct monst *mtmp; { + unsigned old_app = mtmp->mappearance; + uchar old_ap_type = mtmp->m_ap_type; + + mtmp->m_ap_type = M_AP_NOTHING; + mtmp->mappearance = 0; + /* * Discovered mimics don't block light. */ - if ((mtmp->m_ap_type == M_AP_FURNITURE && - (mtmp->mappearance==S_hcdoor || mtmp->mappearance==S_vcdoor))|| - (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance == BOULDER)) - unblock_point(mtmp->mx,mtmp->my); + if (((old_ap_type == M_AP_FURNITURE && + (old_app == S_hcdoor || old_app == S_vcdoor)) || + (old_ap_type == M_AP_OBJECT && old_app == BOULDER)) && + !does_block(mtmp->mx, mtmp->my, &levl[mtmp->mx][mtmp->my])) + unblock_point(mtmp->mx, mtmp->my); - mtmp->m_ap_type = M_AP_NOTHING; - mtmp->mappearance = 0; newsym(mtmp->mx,mtmp->my); } @@ -2086,7 +2152,8 @@ mcham = (int) mtmp->cham; if (mcham) { mtmp->cham = CHAM_ORDINARY; - (void) newcham(mtmp, &mons[cham_to_pm[mcham]], FALSE); + (void) newcham(mtmp, &mons[cham_to_pm[mcham]], + FALSE, FALSE); } if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN) new_were(mtmp); @@ -2129,7 +2196,7 @@ mcham = (int) mon->cham; if (mcham) { mon->cham = CHAM_ORDINARY; - (void) newcham(mon, &mons[cham_to_pm[mcham]], FALSE); + (void) newcham(mon, &mons[cham_to_pm[mcham]], FALSE, FALSE); } else if (is_were(mon->data) && !is_human(mon->data)) { new_were(mon); } @@ -2249,14 +2316,23 @@ /* make a chameleon look like a new monster; returns 1 if it actually changed */ int -newcham(mtmp, mdat, polyspot) +newcham(mtmp, mdat, polyspot, msg) struct monst *mtmp; struct permonst *mdat; boolean polyspot; /* change is the result of wand or spell of polymorph */ +boolean msg; /* "The oldmon turns into a newmon!" */ { int mhp, hpn, hpd; int mndx, tryct; struct permonst *olddata = mtmp->data; + char oldname[BUFSZ]; + + if (msg) { + /* like Monnam() but never mention saddle */ + Strcpy(oldname, x_monnam(mtmp, ARTICLE_THE, (char *)0, + SUPPRESS_SADDLE, FALSE)); + oldname[0] = highc(oldname[0]); + } /* mdat = 0 -> caller wants a random monster shape */ tryct = 0; @@ -2363,6 +2439,9 @@ mtmp->mhp = 1; /* almost dead */ } expels(mtmp, olddata, FALSE); + } else { + /* update swallow glyphs for new monster */ + swallowed(0); } } else if (!sticks(mdat) && !sticks(youmonst.data)) unstuck(mtmp); @@ -2385,11 +2464,20 @@ newsym(mtmp->mx,mtmp->my); + if (msg) { + uchar save_mnamelth = mtmp->mnamelth; + mtmp->mnamelth = 0; + pline("%s turns into %s!", oldname, + mdat == &mons[PM_GREEN_SLIME] ? "slime" : + x_monnam(mtmp, ARTICLE_A, (char*)0, SUPPRESS_SADDLE, FALSE)); + mtmp->mnamelth = save_mnamelth; + } + + possibly_unwield(mtmp, polyspot); /* might lose use of weapon */ mon_break_armor(mtmp, polyspot); if (!(mtmp->misc_worn_check & W_ARMG)) mselftouch(mtmp, "No longer petrify-resistant, ", !flags.mon_moving); - possibly_unwield(mtmp); m_dowear(mtmp, FALSE); /* This ought to re-test can_carry() on each item in the inventory @@ -2430,6 +2518,11 @@ can_be_hatched(mnum) int mnum; { + /* ranger quest nemesis has the oviparous bit set, making it + be possible to wish for eggs of that unique monster; turn + such into ordinary eggs rather than forbidding them outright */ + if (mnum == PM_SCORPIUS) mnum = PM_SCORPION; + mnum = little_to_big(mnum); /* * Queen bees lay killer bee eggs (usually), but killer bees don't @@ -2535,7 +2628,7 @@ mndx = monsndx(mtmp->data); if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham[mtmp->cham]) { if (mtmp->cham && !kill_cham[mtmp->cham]) - (void) newcham(mtmp, (struct permonst *)0, FALSE); + (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); else mondead(mtmp); } @@ -2634,6 +2727,28 @@ mtmp->mpeaceful = 1; } } + +void +mimic_hit_msg(mtmp, otyp) +struct monst *mtmp; +short otyp; +{ + short ap = mtmp->mappearance; + + switch(mtmp->m_ap_type) { + case M_AP_NOTHING: + case M_AP_FURNITURE: + case M_AP_MONSTER: + break; + case M_AP_OBJECT: + if (otyp == SPE_HEALING || otyp == SPE_EXTRA_HEALING) { + pline("%s seems a more vivid %s than before.", + The(simple_typename(ap)), + c_obj_colors[objects[ap].oc_color]); + } + break; + } +} #endif /* OVLB */ /*mon.c*/ diff -Naurd ../nethack-3.4.0/src/mondata.c ./src/mondata.c --- ../nethack-3.4.0/src/mondata.c Wed Mar 20 23:43:10 2002 +++ ./src/mondata.c Mon Feb 24 15:25:05 2003 @@ -6,10 +6,6 @@ #include "eshk.h" #include "epri.h" -/* fake attack and damage types */ -#define AT_ANY (-1) -#define AD_ANY (-1) - /* These routines provide basic data for any type of monster. */ #ifdef OVLB @@ -251,6 +247,16 @@ (ptr->mlet==S_IMP && ptr != &mons[PM_TENGU]))); } +/* true iff the type of monster pass through iron bars */ +boolean +passes_bars(mptr) +struct permonst *mptr; +{ + return (boolean) (passes_walls(mptr) || amorphous(mptr) || + is_whirly(mptr) || verysmall(mptr) || + (slithy(mptr) && !bigmonst(mptr))); +} + #endif /* OVL0 */ #ifdef OVL1 @@ -295,6 +301,28 @@ attacktype(ptr,AT_HUGS))); } +/* number of horns this type of monster has on its head */ +int +num_horns(ptr) +struct permonst *ptr; +{ + switch (monsndx(ptr)) { + case PM_HORNED_DEVIL: /* ? "more than one" */ + case PM_MINOTAUR: + case PM_ASMODEUS: + case PM_BALROG: + return 2; + case PM_WHITE_UNICORN: + case PM_GRAY_UNICORN: + case PM_BLACK_UNICORN: + case PM_KI_RIN: + return 1; + default: + break; + } + return 0; +} + struct attack * dmgtype_fromattack(ptr, dtyp, atyp) struct permonst *ptr; @@ -359,7 +387,7 @@ /* ought to switch this to use `fmt_ptr' */ panic("monsndx - could not index monster (%lx)", (unsigned long)ptr); - return FALSE; /* will not get here */ + return NON_PM; /* will not get here */ } return(i); @@ -521,6 +549,11 @@ {PM_KOBOLD, PM_LARGE_KOBOLD}, {PM_LARGE_KOBOLD, PM_KOBOLD_LORD}, {PM_GNOME, PM_GNOME_LORD}, {PM_GNOME_LORD, PM_GNOME_KING}, {PM_DWARF, PM_DWARF_LORD}, {PM_DWARF_LORD, PM_DWARF_KING}, + {PM_MIND_FLAYER, PM_MASTER_MIND_FLAYER}, + {PM_ORC, PM_ORC_CAPTAIN}, {PM_HILL_ORC, PM_ORC_CAPTAIN}, + {PM_MORDOR_ORC, PM_ORC_CAPTAIN}, {PM_URUK_HAI, PM_ORC_CAPTAIN}, + {PM_SEWER_RAT, PM_GIANT_RAT}, + {PM_CAVE_SPIDER, PM_GIANT_SPIDER}, {PM_OGRE, PM_OGRE_LORD}, {PM_OGRE_LORD, PM_OGRE_KING}, {PM_ELF, PM_ELF_LORD}, {PM_WOODLAND_ELF, PM_ELF_LORD}, {PM_GREEN_ELF, PM_ELF_LORD}, {PM_GREY_ELF, PM_ELF_LORD}, @@ -605,6 +638,19 @@ return montype; } +/* + * Return the permonst ptr for the race of the monster. + * Returns correct pointer for non-polymorphed and polymorphed + * player. It does not return a pointer to player role character. + */ +const struct permonst * +raceptr(mtmp) +struct monst *mtmp; +{ + if (mtmp == &youmonst && !Upolyd) return(&mons[urace.malenum]); + else return(mtmp->data); +} + static const char *levitate[4] = { "float", "Float", "wobble", "Wobble" }; static const char *flys[4] = { "fly", "Fly", "flutter", "Flutter" }; static const char *flyl[4] = { "fly", "Fly", "stagger", "Stagger" }; @@ -653,6 +699,45 @@ } +/* return a phrase describing the effect of fire attack on a type of monster */ +const char * +on_fire(mptr, mattk) +struct permonst *mptr; +struct attack *mattk; +{ + const char *what; + + switch (monsndx(mptr)) { + case PM_FLAMING_SPHERE: + case PM_FIRE_VORTEX: + case PM_FIRE_ELEMENTAL: + what = "already on fire"; + break; + case PM_WATER_ELEMENTAL: + case PM_FOG_CLOUD: + case PM_STEAM_VORTEX: + what = "boiling"; + break; + case PM_ICE_VORTEX: + case PM_GLASS_GOLEM: + what = "melting"; + break; + case PM_STONE_GOLEM: + case PM_CLAY_GOLEM: + case PM_GOLD_GOLEM: + case PM_AIR_ELEMENTAL: + case PM_EARTH_ELEMENTAL: + case PM_DUST_VORTEX: + case PM_ENERGY_VORTEX: + what = "heating up"; + break; + default: + what = (mattk->aatyp == AT_HUGS) ? "being roasted" : "on fire"; + break; + } + return what; +} + #endif /* OVLB */ /*mondata.c*/ diff -Naurd ../nethack-3.4.0/src/monmove.c ./src/monmove.c --- ../nethack-3.4.0/src/monmove.c Wed Mar 20 23:43:11 2002 +++ ./src/monmove.c Mon Feb 24 15:25:05 2003 @@ -1,10 +1,11 @@ -/* SCCS Id: @(#)monmove.c 3.4 2000/08/16 */ +/* SCCS Id: @(#)monmove.c 3.4 2002/04/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mfndpos.h" #include "artifact.h" +#include "epri.h" extern boolean notonhead; @@ -48,10 +49,9 @@ watch_on_duty(mtmp) register struct monst *mtmp; { - register s_level *slev = Is_special(&u.uz); int x, y; - if(slev && slev->flags.town && mtmp->mpeaceful && + if(mtmp->mpeaceful && in_town(u.ux+u.dx, u.uy+u.dy) && mtmp->mcansee && m_canseeu(mtmp) && !rn2(3)) { if(picking_lock(&x, &y) && IS_DOOR(levl[x][y].typ) && @@ -131,9 +131,9 @@ struct monst *mtmp; { if (mtmp->isshk || mtmp->isgd || mtmp->iswiz || !mtmp->mcansee || - mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN || - is_lminion(mtmp->data) || is_rider(mtmp->data) || - mtmp->data == &mons[PM_MINOTAUR]) + mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN || + is_lminion(mtmp) || mtmp->data == &mons[PM_ANGEL] || + is_rider(mtmp->data) || mtmp->data == &mons[PM_MINOTAUR]) return(FALSE); return (boolean)(sobj_at(SCR_SCARE_MONSTER, x, y) @@ -491,7 +491,7 @@ /* arbitrary distance restriction to keep monster far away from you from having cast dozens of sticks-to-snakes or similar spells by the time you reach it */ - if (dist2(mtmp->mx, mtmp->my, u.ux, u.uy) <= 64 && !mtmp->mspec_used) { + if (dist2(mtmp->mx, mtmp->my, u.ux, u.uy) <= 49 && !mtmp->mspec_used) { struct attack *a; for (a = &mdat->mattk[0]; a < &mdat->mattk[NATTK]; a++) { @@ -625,12 +625,10 @@ /* Not necessary if m_move called from this file, but necessary in * other calls of m_move (ex. leprechauns dodging) */ - can_tunnel = tunnels(ptr) && #ifdef REINCARNATION - !Is_rogue_level(&u.uz) && + if (!Is_rogue_level(&u.uz)) #endif - (!needspick(ptr) || m_carrying(mtmp, PICK_AXE) || - (m_carrying(mtmp, DWARVISH_MATTOCK) && !which_armor(mtmp, W_ARMS))); + can_tunnel = tunnels(ptr); can_open = !(nohands(ptr) || verysmall(ptr)); can_unlock = ((can_open && m_carrying(mtmp, SKELETON_KEY)) || mtmp->iswiz || is_rider(ptr)); @@ -822,7 +820,7 @@ (mtoo->mappearance && !mtoo->iswiz) || !mtoo->data->mmove)) continue; - if(((likegold && otmp->oclass == GOLD_CLASS) || + if(((likegold && otmp->oclass == COIN_CLASS) || (likeobjs && index(practical, otmp->oclass) && (otmp->otyp != CORPSE || (ptr->mlet == S_NYMPH && !is_rider(&mons[otmp->corpsenm])))) || @@ -875,9 +873,10 @@ } } + /* don't tunnel if hostile and close enough to prefer a weapon */ if (can_tunnel && needspick(ptr) && - (mw_tmp = MON_WEP(mtmp)) != 0 && !is_pick(mw_tmp) && - mw_tmp->cursed && mtmp->weapon_check == NO_WEAPON_WANTED) + ((!mtmp->mpeaceful || Conflict) && + dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8)) can_tunnel = FALSE; nix = omx; @@ -890,6 +889,7 @@ /* unicorn may not be able to avoid hero on a noteleport level */ if (is_unicorn(ptr) && !level.flags.noteleport) flag |= NOTONL; if (passes_walls(ptr)) flag |= (ALLOW_WALL | ALLOW_ROCK); + if (passes_bars(ptr)) flag |= ALLOW_BARS; if (can_tunnel) flag |= ALLOW_DIG; if (is_human(ptr) || ptr == &mons[PM_MINOTAUR]) flag |= ALLOW_SSM; if (is_undead(ptr) && ptr->mlet != S_GHOST) flag |= NOGARLIC; @@ -951,11 +951,20 @@ if (mmoved==1 && (u.ux != nix || u.uy != niy) && itsstuck(mtmp)) return(3); - if(IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy) && - mmoved==1 && can_tunnel && needspick(ptr) && - (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp))) { - mtmp->weapon_check = NEED_PICK_AXE; - if (mon_wield_item(mtmp)) + if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) || + closed_door(nix, niy)) && + mmoved==1 && can_tunnel && needspick(ptr)) { + if (closed_door(nix, niy)) { + if (!(mw_tmp = MON_WEP(mtmp)) || + !is_pick(mw_tmp) || !is_axe(mw_tmp)) + mtmp->weapon_check = NEED_PICK_OR_AXE; + } else if (IS_TREE(levl[nix][niy].typ)) { + if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) + mtmp->weapon_check = NEED_AXE; + } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { + mtmp->weapon_check = NEED_PICK_AXE; + } + if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp)) return(3); } /* If ALLOW_U is set, either it's trying to attack you, or it @@ -1048,10 +1057,10 @@ if(here->doormask & (D_LOCKED|D_CLOSED) && amorphous(ptr)) { if (flags.verbose && canseemon(mtmp)) - pline("%s %ss under the door.", Monnam(mtmp), + pline("%s %s under the door.", Monnam(mtmp), (ptr == &mons[PM_FOG_CLOUD] || ptr == &mons[PM_YELLOW_LIGHT]) - ? "flow" : "ooze"); + ? "flows" : "oozes"); } else if(here->doormask & D_LOCKED && can_unlock) { if(btrapped) { here->doormask = D_NODOOR; @@ -1110,6 +1119,12 @@ if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE)) add_damage(mtmp->mx, mtmp->my, 0L); } + } else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) { + if (flags.verbose && canseemon(mtmp)) + Norep("%s %s %s the iron bars.", Monnam(mtmp), + /* pluralization fakes verb conjugation */ + makeplural(locomotion(ptr, "pass")), + passes_walls(ptr) ? "through" : "between"); } /* possibly dig */ @@ -1187,6 +1202,9 @@ (is_pool(mtmp->mx, mtmp->my) && !Is_waterlevel(&u.uz)); newsym(mtmp->mx, mtmp->my); } + if (mtmp->isshk) { + after_shk_move(mtmp); + } } return(mmoved); } @@ -1307,7 +1325,7 @@ int typ = obj->otyp; #ifdef GOLDOBJ - if (typ == GOLD_CLASS && obj->quan > 100L) return FALSE; + if (typ == COIN_CLASS && obj->quan > 100L) return FALSE; #endif if (obj->oclass != GEM_CLASS && !(typ >= ARROW && typ <= BOOMERANG) && diff -Naurd ../nethack-3.4.0/src/monst.c ./src/monst.c --- ../nethack-3.4.0/src/monst.c Wed Mar 20 23:43:11 2002 +++ ./src/monst.c Mon Feb 24 15:25:05 2003 @@ -1194,7 +1194,7 @@ NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE, - M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_BRIGHT_CYAN), + M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, DRAGON_SILVER), #if 0 /* DEFERRED */ MON("baby shimmering dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, @@ -1271,7 +1271,7 @@ M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, - 0, CLR_BRIGHT_CYAN), + 0, DRAGON_SILVER), #if 0 /* DEFERRED */ MON("shimmering dragon", S_DRAGON, LVL(15, 9, -1, 20, 4), (G_GENO|1), @@ -2060,7 +2060,7 @@ M1_BREATHLESS|M1_WALLWALK|M1_THICK_HIDE|M1_METALLIVORE, M2_HOSTILE|M2_STRONG, 0, CLR_BROWN), /* - * Yeti, apes and other large beasts + * Apelike beasts */ MON("monkey", S_YETI, LVL(2, 12, 6, 0, 0), (G_GENO|1), @@ -3138,7 +3138,7 @@ LVL(20, 12, 0, 30, -20), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0, + SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_MALE|M2_GREEDY| M2_JEWELS|M2_COLLECT|M2_MAGIC, @@ -3189,8 +3189,8 @@ A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK), - SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE), MR_FIRE|MR_POISON, 0, - M1_FLY|M1_SEE_INVIS|M1_POIS, + SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE), + MR_FIRE|MR_POISON|MR_STONE, 0, M1_FLY|M1_SEE_INVIS|M1_POIS, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, CLR_RED), MON("Thoth Amon", S_HUMAN, @@ -3198,7 +3198,7 @@ A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 1, 4), NO_ATTK, NO_ATTK), - SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON, 0, + SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON|MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_STRONG|M2_MALE|M2_STALK|M2_HOSTILE| M2_NASTY|M2_COLLECT|M2_MAGIC, @@ -3233,7 +3233,7 @@ LVL(18, 12, 0, 0, -15), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4, 8), ATTK(AT_WEAP, AD_PHYS, 4, 8), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1900, 700, 0, MS_NEMESIS, MZ_HUGE), 0, 0, + SIZ(1900, 700, 0, MS_NEMESIS, MZ_HUGE), MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_STALK|M2_HOSTILE| M2_NASTY|M2_MALE|M2_JEWELS|M2_COLLECT, @@ -3243,7 +3243,8 @@ A(ATTK(AT_BREA, AD_FIRE, 8, 6), ATTK(AT_BITE, AD_PHYS, 4, 8), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK ), - SIZ(WT_DRAGON, 1600, 0, MS_NEMESIS, MZ_GIGANTIC), MR_FIRE, MR_FIRE, + SIZ(WT_DRAGON, 1600, 0, MS_NEMESIS, MZ_GIGANTIC), + MR_FIRE|MR_STONE, MR_FIRE, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE|M1_SEE_INVIS, M2_NOPOLY|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_STALK| M2_GREEDY|M2_JEWELS|M2_MAGIC, @@ -3253,7 +3254,8 @@ A(ATTK(AT_CLAW, AD_PHYS, 16, 2), ATTK(AT_CLAW, AD_PHYS, 16, 2), ATTK(AT_MAGC, AD_CLRC, 0, 0), ATTK(AT_CLAW, AD_SAMU, 1, 4), NO_ATTK, NO_ATTK), - SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON, MR_POISON, + SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), + MR_POISON|MR_STONE, MR_POISON, M1_HUMANOID|M1_HERBIVORE|M1_SEE_INVIS, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_NASTY| M2_STALK|M2_COLLECT|M2_MAGIC, @@ -3263,8 +3265,8 @@ A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK), - SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE), MR_FIRE|MR_POISON, 0, - M1_FLY|M1_SEE_INVIS|M1_POIS, + SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE), + MR_FIRE|MR_POISON|MR_STONE, 0, M1_FLY|M1_SEE_INVIS|M1_POIS, M2_NOPOLY|M2_DEMON|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK| M2_NASTY|M2_COLLECT, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, CLR_RED), @@ -3272,7 +3274,7 @@ LVL(15, 12, 10, 0, -15), (G_NOGEN|G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 6), ATTK(AT_STNG, AD_DISE, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(750, 350, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON, MR_POISON, + SIZ(750, 350, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON|MR_STONE, MR_POISON, M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_POIS|M1_CARNIVORE, M2_NOPOLY|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK|M2_NASTY| M2_COLLECT|M2_MAGIC, @@ -3281,7 +3283,7 @@ LVL(15, 12, 0, 30, 18), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_DRST, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), 0, 0, + SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_HOSTILE|M2_STALK|M2_NASTY| M2_COLLECT|M2_MAGIC, @@ -3293,7 +3295,7 @@ LVL(15, 12, 0, 40, -13), (G_NOGEN|G_UNIQ|G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), 0, 0, + SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK| M2_NASTY|M2_MALE|M2_COLLECT|M2_MAGIC, @@ -3307,7 +3309,7 @@ LVL(15, 12, 2, 50, 12), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2,10), ATTK(AT_WEAP, AD_PHYS, 2,10), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(2250, 850, 0, MS_NEMESIS, MZ_HUGE), MR_FIRE, MR_FIRE, + SIZ(2250, 850, 0, MS_NEMESIS, MZ_HUGE), MR_FIRE|MR_STONE, MR_FIRE, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_GIANT|M2_MALE|M2_PNAME|M2_HOSTILE|M2_STALK| M2_STRONG|M2_NASTY|M2_ROCKTHROW|M2_JEWELS|M2_COLLECT, @@ -3317,7 +3319,7 @@ A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_SAMU, 1, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK), - SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), 0, 0, + SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_HOSTILE|M2_STALK|M2_NASTY| M2_COLLECT|M2_MAGIC, diff -Naurd ../nethack-3.4.0/src/mplayer.c ./src/mplayer.c --- ../nethack-3.4.0/src/mplayer.c Wed Mar 20 23:43:11 2002 +++ ./src/mplayer.c Mon Feb 24 15:25:05 2003 @@ -305,7 +305,7 @@ do { x = rn1(COLNO-4, 2); y = rnd(ROWNO-2); - } while(!goodpos(x, y, &fakemon) && tryct++ <= 50); + } while(!goodpos(x, y, &fakemon, 0) && tryct++ <= 50); /* if pos not found in 50 tries, don't bother to continue */ if(tryct > 50) return; diff -Naurd ../nethack-3.4.0/src/mthrowu.c ./src/mthrowu.c --- ../nethack-3.4.0/src/mthrowu.c Wed Mar 20 23:43:11 2002 +++ ./src/mthrowu.c Mon Feb 24 15:25:05 2003 @@ -186,9 +186,9 @@ if (ismimic) seemimic(mtmp); mtmp->msleeping = 0; if (vis) hit(distant_name(otmp,mshot_xname), mtmp, exclam(damage)); - else if (verbose) pline("It is hit%s", exclam(damage)); + else if (verbose) pline("%s is hit%s", Monnam(mtmp), exclam(damage)); - if (otmp->opoisoned) { + if (otmp->opoisoned && is_poisonable(otmp)) { if (resists_poison(mtmp)) { if (vis) pline_The("poison doesn't seem to affect %s.", mon_nam(mtmp)); @@ -221,9 +221,12 @@ if (mtmp->mhp < 1) { if (vis || verbose) pline("%s is %s!", Monnam(mtmp), - (nonliving(mtmp->data) || !vis) + (nonliving(mtmp->data) || !canspotmon(mtmp)) ? "destroyed" : "killed"); - if (!flags.mon_moving) xkilled(mtmp,0); + /* don't blame hero for unknown rolling boulder trap */ + if (!flags.mon_moving && + (otmp->otyp != BOULDER || range >= 0 || !otmp->otrapped)) + xkilled(mtmp,0); else mondied(mtmp); } @@ -299,16 +302,26 @@ } dx = rn2(3)-1; dy = rn2(3)-1; - /* pre-check validity of new direction */ - if((!dx && !dy) - || !isok(bhitpos.x+dx,bhitpos.y+dy) - /* missile hits the wall */ - || IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ)) { + /* check validity of new direction */ + if (!dx && !dy) { (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); return; } } + /* pre-check for doors, walls and boundaries. + Also need to pre-check for bars regardless of direction; + the random chance for small objects hitting bars is + skipped when reaching them at point blank range */ + if (!isok(bhitpos.x+dx,bhitpos.y+dy) + || IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ) + || closed_door(bhitpos.x+dx, bhitpos.y+dy) + || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS && + hits_bars(&singleobj, bhitpos.x, bhitpos.y, 0, 0))) { + (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); + return; + } + /* Note: drop_throw may destroy singleobj. Since obj must be destroyed * early to avoid the dagger bug, anyone who modifies this code should * be careful not to use either one after it's been freed. @@ -377,7 +390,8 @@ if (dam < 1) dam = 1; hitu = thitu(hitv, dam, singleobj, (char *)0); } - if (hitu && singleobj->opoisoned) { + if (hitu && singleobj->opoisoned && + is_poisonable(singleobj)) { char onmbuf[BUFSZ], knmbuf[BUFSZ]; struct obj otmp; unsigned save_ocknown; @@ -433,12 +447,18 @@ || !isok(bhitpos.x+dx,bhitpos.y+dy) /* missile hits the wall */ || IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ) + /* missile hit closed door */ + || closed_door(bhitpos.x+dx, bhitpos.y+dy) + /* missile might hit iron bars */ + || (levl[bhitpos.x+dx][bhitpos.y+dy].typ == IRONBARS && + hits_bars(&singleobj, bhitpos.x, bhitpos.y, !rn2(5), 0)) #ifdef SINKS /* Thrown objects "sink" */ || IS_SINK(levl[bhitpos.x][bhitpos.y].typ) #endif ) { - (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); + if (singleobj) /* hits_bars might have destroyed it */ + (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); break; } tmp_at(bhitpos.x, bhitpos.y); @@ -469,10 +489,10 @@ obj->owt = weight(obj); } else { obj_extract_self(obj); - possibly_unwield(mon); + possibly_unwield(mon, FALSE); if (obj->owornmask) { mon->misc_worn_check &= ~obj->owornmask; - update_mon_intrinsics(mon, obj, FALSE); + update_mon_intrinsics(mon, obj, FALSE, FALSE); } obfree(obj, (struct obj*) 0); } @@ -743,6 +763,83 @@ return((struct obj *) 0); } +/* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */ +boolean +hits_bars(obj_p, x, y, always_hit, whodidit) +struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */ +int x, y; +int always_hit; /* caller can force a hit for items which would fit through */ +int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */ +{ + struct obj *otmp = *obj_p; + int obj_type = otmp->otyp; + boolean hits = always_hit; + + if (!hits) + switch (otmp->oclass) { + case WEAPON_CLASS: + { + int oskill = objects[obj_type].oc_skill; + + hits = (oskill != -P_BOW && oskill != -P_CROSSBOW && + oskill != -P_DART && oskill != -P_SHURIKEN && + oskill != P_SPEAR && oskill != P_JAVELIN && + oskill != P_KNIFE); /* but not dagger */ + break; + } + case ARMOR_CLASS: + hits = (objects[obj_type].oc_armcat != ARM_GLOVES); + break; + case TOOL_CLASS: + hits = (obj_type != SKELETON_KEY && + obj_type != LOCK_PICK && +#ifdef TOURIST + obj_type != CREDIT_CARD && +#endif + obj_type != TALLOW_CANDLE && + obj_type != WAX_CANDLE && + obj_type != LENSES && + obj_type != TIN_WHISTLE && + obj_type != MAGIC_WHISTLE); + break; + case ROCK_CLASS: /* includes boulder */ + if (obj_type != STATUE || + mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE; + break; + case FOOD_CLASS: + if (obj_type == CORPSE && + mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE; + else + hits = (obj_type == MEAT_STICK || + obj_type == HUGE_CHUNK_OF_MEAT); + break; + case SPBOOK_CLASS: + case WAND_CLASS: + case BALL_CLASS: + case CHAIN_CLASS: + hits = TRUE; + break; + default: + break; + } + + if (hits && whodidit != -1) { + if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y)) + *obj_p = otmp = 0; /* object is now gone */ + /* breakage makes its own noises */ + else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL) + pline("Whang!"); + else if (otmp->oclass == COIN_CLASS || + objects[obj_type].oc_material == GOLD || + objects[obj_type].oc_material == SILVER) + pline("Clink!"); + else + pline("Clonk!"); + } + + return hits; +} + #endif /* OVL0 */ /*mthrowu.c*/ diff -Naurd ../nethack-3.4.0/src/muse.c ./src/muse.c --- ../nethack-3.4.0/src/muse.c Wed Mar 20 23:43:11 2002 +++ ./src/muse.c Mon Feb 24 15:25:05 2003 @@ -445,10 +445,19 @@ nomore(MUSE_WAN_TELEPORTATION_SELF); nomore(MUSE_WAN_TELEPORTATION); if(obj->otyp == WAN_TELEPORTATION && obj->spe > 0) { + /* use the TELEP_TRAP bit to determine if they know + * about noteleport on this level or not. Avoids + * ineffective re-use of teleportation. This does + * mean if the monster leaves the level, they'll know + * about teleport traps. + */ + if (!level.flags.noteleport || + !(mtmp->mtrapseen & (1 << (TELEP_TRAP-1)))) { m.defensive = obj; m.has_defense = (mon_has_amulet(mtmp)) ? MUSE_WAN_TELEPORTATION : MUSE_WAN_TELEPORTATION_SELF; + } } nomore(MUSE_SCR_TELEPORTATION); if(obj->otyp == SCR_TELEPORTATION && mtmp->mcansee @@ -456,8 +465,12 @@ && (!obj->cursed || (!(mtmp->isshk && inhishop(mtmp)) && !mtmp->isgd && !mtmp->ispriest))) { + /* see WAN_TELEPORTATION case above */ + if (!level.flags.noteleport || + !(mtmp->mtrapseen & (1 << (TELEP_TRAP-1)))) { m.defensive = obj; m.has_defense = MUSE_SCR_TELEPORTATION; + } } if (mtmp->data != &mons[PM_PESTILENCE]) { @@ -563,6 +576,9 @@ if (tele_restrict(mtmp)) { /* mysterious force... */ if (vismon && how) /* mentions 'teleport' */ makeknown(how); + /* monster learns that teleportation isn't useful here */ + if (level.flags.noteleport) + mtmp->mtrapseen |= (1 << (TELEP_TRAP-1)); return 2; } if (( @@ -584,6 +600,9 @@ otmp->spe--; m_using = TRUE; mbhit(mtmp,rn1(8,6),mbhitm,bhito,otmp); + /* monster learns that teleportation isn't useful here */ + if (level.flags.noteleport) + mtmp->mtrapseen |= (1 << (TELEP_TRAP-1)); m_using = FALSE; return 2; case MUSE_SCR_TELEPORTATION: @@ -882,6 +901,7 @@ { struct permonst *pm = mtmp->data; int difficulty = monstr[(monsndx(pm))]; + int trycnt = 0; if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data) || pm->mlet == S_GHOST @@ -889,9 +909,12 @@ || pm->mlet == S_KOP # endif ) return 0; + try_again: switch (rn2(8 + (difficulty > 3) + (difficulty > 6) + (difficulty > 8))) { case 6: case 9: + if (level.flags.noteleport && ++trycnt < 2) + goto try_again; if (!rn2(3)) return WAN_TELEPORTATION; /* else FALLTHRU */ case 0: case 1: @@ -1130,7 +1153,7 @@ break; case WAN_CANCELLATION: case SPE_CANCELLATION: - cancel_monst(mtmp, otmp, FALSE, TRUE, FALSE); + (void) cancel_monst(mtmp, otmp, FALSE, TRUE, FALSE); break; } if (reveal_invis) { @@ -1760,13 +1783,13 @@ case MUSE_WAN_POLYMORPH: mzapmsg(mtmp, otmp, TRUE); otmp->spe--; - (void) newcham(mtmp, muse_newcham_mon(mtmp), TRUE); + (void) newcham(mtmp, muse_newcham_mon(mtmp), TRUE, FALSE); if (oseen) makeknown(WAN_POLYMORPH); return 2; case MUSE_POT_POLYMORPH: mquaffmsg(mtmp, otmp); if (vismon) pline("%s suddenly mutates!", Monnam(mtmp)); - (void) newcham(mtmp, muse_newcham_mon(mtmp), FALSE); + (void) newcham(mtmp, muse_newcham_mon(mtmp), FALSE, FALSE); if (oseen) makeknown(POT_POLYMORPH); m_useup(mtmp, otmp); return 2; @@ -1784,7 +1807,7 @@ if (mtmp->wormno) worm_move(mtmp); newsym(trapx, trapy); - (void) newcham(mtmp, (struct permonst *)0, FALSE); + (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); return 2; case MUSE_BULLWHIP: /* attempt to disarm hero */ @@ -2011,6 +2034,11 @@ makeknown(SHIELD_OF_REFLECTION); } return TRUE; + } else if (arti_reflects(MON_WEP(mon))) { + /* due to wielded artifact weapon */ + if (str) + pline(str, s_suffix(mon_nam(mon)), "weapon"); + return TRUE; } else if ((orefl = which_armor(mon, W_AMUL)) && orefl->otyp == AMULET_OF_REFLECTION) { if (str) { @@ -2100,6 +2128,10 @@ int nutrit = (obj->otyp == CORPSE) ? dog_nutrition(mon, obj) : 0; /* also sets meating */ + /* give a " is slowing down" message and also remove + intrinsic speed (comparable to similar effect on the hero) */ + mon_adjust_speed(mon, -3, (struct obj *)0); + if (canseemon(mon)) { long save_quan = obj->quan; diff -Naurd ../nethack-3.4.0/src/music.c ./src/music.c --- ../nethack-3.4.0/src/music.c Wed Mar 20 23:43:12 2002 +++ ./src/music.c Mon Feb 24 15:25:05 2003 @@ -409,7 +409,7 @@ if ((damage = zapyourself(instr, TRUE)) != 0) { char buf[BUFSZ]; Sprintf(buf, "using a magical horn on %sself", uhim()); - losehp(damage, buf, NO_KILLER_PREFIX); + losehp(damage, buf, KILLED_BY); } } else { buzz((instr->otyp == FROST_HORN) ? AD_COLD-1 : AD_FIRE-1, diff -Naurd ../nethack-3.4.0/src/objects.c ./src/objects.c --- ../nethack-3.4.0/src/objects.c Wed Mar 20 23:43:12 2002 +++ ./src/objects.c Mon Feb 24 15:25:05 2003 @@ -321,40 +321,44 @@ /* suits of armor */ /* * There is code in polyself.c that assumes (1) and (2). - * There is code in objnam.c, mon.c, read.c that assumes (2). + * There is code in obj.h, objnam.c, mon.c, read.c that assumes (2). * * (1) The dragon scale mails and the dragon scales are together. * (2) That the order of the dragon scale mail and dragon scales is the * the same defined in monst.c. */ -#define DRGN_ARMR(name,power,cost,ac,color) \ - ARMOR(name,(char *)0,1,0,1,power,0,5,40,cost,ac,0,ARM_SUIT,DRAGON_HIDE,color) -DRGN_ARMR("gray dragon scale mail", ANTIMAGIC, 1200, 1, CLR_GRAY), -DRGN_ARMR("silver dragon scale mail", REFLECTING, 1200, 1, SILVER), +#define DRGN_ARMR(name,mgc,power,cost,ac,color) \ + ARMOR(name,(char *)0,1,mgc,1,power,0,5,40,cost,ac,0,ARM_SUIT,DRAGON_HIDE,color) +/* 3.4.1: dragon scale mail reclassified as "magic" since magic is + needed to create them */ +DRGN_ARMR("gray dragon scale mail", 1, ANTIMAGIC, 1200, 1, CLR_GRAY), +DRGN_ARMR("silver dragon scale mail", 1, REFLECTING, 1200, 1, DRAGON_SILVER), #if 0 /* DEFERRED */ -DRGN_ARMR("shimmering dragon scale mail", DISPLACED, 1200, 1, CLR_CYAN), +DRGN_ARMR("shimmering dragon scale mail", 1, DISPLACED, 1200, 1, CLR_CYAN), #endif -DRGN_ARMR("red dragon scale mail", FIRE_RES, 900, 1, CLR_RED), -DRGN_ARMR("white dragon scale mail", COLD_RES, 900, 1, CLR_WHITE), -DRGN_ARMR("orange dragon scale mail", SLEEP_RES, 900, 1, CLR_ORANGE), -DRGN_ARMR("black dragon scale mail", DISINT_RES, 1200, 1, CLR_BLACK), -DRGN_ARMR("blue dragon scale mail", SHOCK_RES, 900, 1, CLR_BLUE), -DRGN_ARMR("green dragon scale mail", POISON_RES, 900, 1, CLR_GREEN), -DRGN_ARMR("yellow dragon scale mail", ACID_RES, 900, 1, CLR_YELLOW), +DRGN_ARMR("red dragon scale mail", 1, FIRE_RES, 900, 1, CLR_RED), +DRGN_ARMR("white dragon scale mail", 1, COLD_RES, 900, 1, CLR_WHITE), +DRGN_ARMR("orange dragon scale mail", 1, SLEEP_RES, 900, 1, CLR_ORANGE), +DRGN_ARMR("black dragon scale mail", 1, DISINT_RES, 1200, 1, CLR_BLACK), +DRGN_ARMR("blue dragon scale mail", 1, SHOCK_RES, 900, 1, CLR_BLUE), +DRGN_ARMR("green dragon scale mail", 1, POISON_RES, 900, 1, CLR_GREEN), +DRGN_ARMR("yellow dragon scale mail", 1, ACID_RES, 900, 1, CLR_YELLOW), /* For now, only dragons leave these. */ -DRGN_ARMR("gray dragon scales", ANTIMAGIC, 700, 7, CLR_GRAY), -DRGN_ARMR("silver dragon scales", REFLECTING, 700, 7, SILVER), +/* 3.4.1: dragon scales left classified as "non-magic"; they confer + magical properties but are produced "naturally" */ +DRGN_ARMR("gray dragon scales", 0, ANTIMAGIC, 700, 7, CLR_GRAY), +DRGN_ARMR("silver dragon scales", 0, REFLECTING, 700, 7, DRAGON_SILVER), #if 0 /* DEFERRED */ -DRGN_ARMR("shimmering dragon scales", DISPLACED, 700, 7, CLR_CYAN), +DRGN_ARMR("shimmering dragon scales", 0, DISPLACED, 700, 7, CLR_CYAN), #endif -DRGN_ARMR("red dragon scales", FIRE_RES, 500, 7, CLR_RED), -DRGN_ARMR("white dragon scales", COLD_RES, 500, 7, CLR_WHITE), -DRGN_ARMR("orange dragon scales", SLEEP_RES, 500, 7, CLR_ORANGE), -DRGN_ARMR("black dragon scales", DISINT_RES, 700, 7, CLR_BLACK), -DRGN_ARMR("blue dragon scales", SHOCK_RES, 500, 7, CLR_BLUE), -DRGN_ARMR("green dragon scales", POISON_RES, 500, 7, CLR_GREEN), -DRGN_ARMR("yellow dragon scales", ACID_RES, 500, 7, CLR_YELLOW), +DRGN_ARMR("red dragon scales", 0, FIRE_RES, 500, 7, CLR_RED), +DRGN_ARMR("white dragon scales", 0, COLD_RES, 500, 7, CLR_WHITE), +DRGN_ARMR("orange dragon scales", 0, SLEEP_RES, 500, 7, CLR_ORANGE), +DRGN_ARMR("black dragon scales", 0, DISINT_RES, 700, 7, CLR_BLACK), +DRGN_ARMR("blue dragon scales", 0, SHOCK_RES, 500, 7, CLR_BLUE), +DRGN_ARMR("green dragon scales", 0, POISON_RES, 500, 7, CLR_GREEN), +DRGN_ARMR("yellow dragon scales", 0, ACID_RES, 500, 7, CLR_YELLOW), #undef DRGN_ARMR ARMOR("plate mail", (char *)0, @@ -647,6 +651,7 @@ 1, 0, 0, 20, 100, 50, 6, 3, WHACK, P_PICK_AXE, IRON, HI_METAL), WEPTOOL("grappling hook", "iron hook", 0, 0, 0, 5, 30, 50, 2, 6, WHACK, P_FLAIL, IRON, HI_METAL), +/* 3.4.1: unicorn horn left classified as "magic" */ WEPTOOL("unicorn horn", (char *)0, 1, 1, 1, 0, 20, 100, 12, 12, PIERCE, P_UNICORN_HORN, BONE, CLR_WHITE), @@ -875,7 +880,7 @@ /* coins ... - so far, gold is all there is */ #define COIN(name,prob,metal,worth) OBJECT( \ OBJ(name,(char *)0), BITS(0,1,0,0,0,0,0,0,0,0,0,P_NONE,metal), 0, \ - GOLD_CLASS, prob, 0, 1, worth, 0, 0, 0, 0, 0, HI_GOLD ) + COIN_CLASS, prob, 0, 1, worth, 0, 0, 0, 0, 0, HI_GOLD ) COIN("gold piece", 1000, GOLD,1), #undef COIN @@ -921,6 +926,10 @@ GEM("worthless piece of green glass", "green", 77, 1, 0, 6, 5, GLASS, CLR_GREEN), GEM("worthless piece of violet glass", "violet", 77, 1, 0, 6, 5, GLASS, CLR_MAGENTA), +/* Placement note: there is a wishable subrange for + * "gray stones" in the o_ranges[] array in objnam.c + * that is currently everything between luckstones and flint (inclusive). + */ ROCK("luckstone", "gray", 0, 10, 10, 60, 3, 3, 1, 10, 7, MINERAL, CLR_GRAY), ROCK("loadstone", "gray", 0, 10, 500, 1, 3, 3, 1, 10, 6, MINERAL, CLR_GRAY), ROCK("touchstone", "gray", 0, 8, 10, 45, 3, 3, 1, 10, 6, MINERAL, CLR_GRAY), diff -Naurd ../nethack-3.4.0/src/objnam.c ./src/objnam.c --- ../nethack-3.4.0/src/objnam.c Wed Mar 20 23:43:12 2002 +++ ./src/objnam.c Mon Feb 24 15:25:05 2003 @@ -101,7 +101,7 @@ if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp)) actualn = Japanese_item_name(otyp); switch(ocl->oc_class) { - case GOLD_CLASS: + case COIN_CLASS: Strcpy(buf, "coin"); break; case POTION_CLASS: @@ -209,6 +209,24 @@ return str; } +/* convert player specified fruit name into corresponding fruit juice name + ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */ +char * +fruitname(juice) +boolean juice; /* whether or not to append " juice" to the name */ +{ + char *buf = nextobuf(); + const char *fruit_nam = strstri(pl_fruit, " of "); + + if (fruit_nam) + fruit_nam += 4; /* skip past " of " */ + else + fruit_nam = pl_fruit; /* use it as is */ + + Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : ""); + return buf; +} + #endif /* OVLB */ #ifdef OVL1 @@ -231,12 +249,11 @@ buf[0] = '\0'; /* * clean up known when it's tied to oc_name_known, eg after AD_DRIN - * This is only required for unique objects and the Fake AoY since the - * article printed for the object is tied to the combination of the two + * This is only required for unique objects since the article + * printed for the object is tied to the combination of the two * and printing the wrong article gives away information. */ - if (!nn && ocl->oc_uses_known && - (ocl->oc_unique || typ == FAKE_AMULET_OF_YENDOR)) obj->known = 0; + if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0; if (!Blind) obj->dknown = TRUE; if (Role_if(PM_PRIEST)) obj->bknown = TRUE; if (obj_is_pname(obj)) @@ -343,7 +360,7 @@ Sprintf(eos(buf), " of %s meat", mons[obj->corpsenm].mname); } break; - case GOLD_CLASS: + case COIN_CLASS: case CHAIN_CLASS: Strcpy(buf, actualn); break; @@ -573,7 +590,7 @@ #endif if (obj->bknown && - obj->oclass != GOLD_CLASS && + obj->oclass != COIN_CLASS && (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known || (!obj->cursed && !obj->blessed))) { /* allow 'blessed clear potion' if we don't know it's holy water; @@ -780,6 +797,10 @@ not_fully_identified(otmp) register struct obj *otmp; { +#ifdef GOLDOBJ + /* gold doesn't have any interesting attributes [yet?] */ + if (otmp->oclass == COIN_CLASS) return FALSE; /* always fully ID'd */ +#endif /* check fundamental ID hallmarks first */ if (!otmp->known || !otmp->dknown || #ifdef MAIL @@ -868,6 +889,7 @@ strcmp(str, "iron bars") && strcmp(str, "ice")) { if (index(vowels, *str) && + strncmp(str, "one-", 4) && strncmp(str, "useful", 6) && strncmp(str, "unicorn", 7) && strncmp(str, "uranium", 7) && @@ -1007,6 +1029,19 @@ return buf; } +/* various singular words that vtense would otherwise categorize as plural */ +static const char * const special_subjs[] = { + "erinys", + "manes", /* this one is ambiguous */ + "Cyclops", + "Hippocrates", + "Pelias", + "aklys", + "amnesia", + "paralysis", + 0 +}; + /* return form of the verb (input plural) for present tense 3rd person subj */ char * vtense(subj, verb) @@ -1015,8 +1050,8 @@ { char *buf = nextobuf(); int len; - const char *spot; - const char *sp; + const char *sp, *spot; + const char * const *spec; /* * verb is given in plural (without trailing s). Return as input @@ -1032,6 +1067,7 @@ spot = (const char *)0; for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) { if (!strncmp(sp, " of ", 4) || + !strncmp(sp, " from ", 6) || !strncmp(sp, " called ", 8) || !strncmp(sp, " named ", 7) || !strncmp(sp, " labeled ", 9)) { @@ -1039,23 +1075,33 @@ break; } } - len = strlen(subj); + len = (int) strlen(subj); if (!spot) spot = subj + len - 1; /* - * plural: anything that ends in 's', but not '*us'. + * plural: anything that ends in 's', but not '*us' or '*ss'. * Guess at a few other special cases that makeplural creates. */ - if ((*spot == 's' && spot != subj && *(spot-1) != 'u') || + if ((*spot == 's' && spot != subj && + (*(spot-1) != 'u' && *(spot-1) != 's')) || ((spot - subj) >= 4 && !strncmp(spot-3, "eeth", 4)) || ((spot - subj) >= 3 && !strncmp(spot-3, "feet", 4)) || ((spot - subj) >= 2 && !strncmp(spot-1, "ia", 2)) || ((spot - subj) >= 2 && !strncmp(spot-1, "ae", 2))) { - Strcpy(buf, verb); - return buf; + /* check for special cases to avoid false matches */ + len = (int)(spot - subj) + 1; + for (spec = special_subjs; *spec; spec++) + if (!strncmpi(*spec, subj, len)) goto sing; + + return strcpy(buf, verb); } + /* + * 2nd person singular behaves as if plural. + */ + if (!strcmpi(subj, "you")) return strcpy(buf, verb); } + sing: len = strlen(verb); spot = verb + len - 1; @@ -1452,27 +1498,32 @@ Strcpy(p-3, "fe"); return bp; } - if(!BSTRCMP(bp, p-6, "staves")) { Strcpy(p-3, "ff"); return bp; } - if (!BSTRCMPI(bp, p-6, "leaves")) { Strcpy(p-3, "f"); return bp; } + if (!BSTRCMP(bp, p-8, "vortices")) { + Strcpy(p-4, "ex"); + return bp; + } /* note: nurses, axes but boxes */ - if(!BSTRCMP(bp, p-5, "boxes")) { - p[-2] = 0; + if (!BSTRCMP(bp, p-5, "boxes") || + !BSTRCMP(bp, p-4, "ches")) { + p[-2] = '\0'; return bp; } + if (!BSTRCMP(bp, p-6, "gloves") || !BSTRCMP(bp, p-6, "lenses") || !BSTRCMP(bp, p-5, "shoes") || !BSTRCMP(bp, p-6, "scales")) return bp; + } else if (!BSTRCMP(bp, p-5, "boots") || !BSTRCMP(bp, p-9, "gauntlets") || !BSTRCMP(bp, p-6, "tricks") || @@ -1486,15 +1537,24 @@ #ifdef WIZARD !BSTRCMP(bp, p-9, "iron bars") || #endif - !BSTRCMP(bp, p-5, "aklys")) + !BSTRCMP(bp, p-5, "aklys") || + !BSTRCMP(bp, p-6, "fungus")) return bp; mins: - p[-1] = 0; + p[-1] = '\0'; + } else { + if(!BSTRCMP(bp, p-5, "teeth")) { Strcpy(p-5, "tooth"); return bp; } + + if (!BSTRCMP(bp, p-5, "fungi")) { + Strcpy(p-5, "fungus"); + return bp; + } + /* here we cannot find the plural suffix */ } return bp; @@ -1507,6 +1567,15 @@ const char *o_str; /* from objects[], so is in canonical form */ boolean retry_inverted; /* optional extra "of" handling */ { + /* special case: wizards can wish for traps. The object is "beartrap" + * and the trap is "bear trap", so to let wizards wish for both we + * must not fuzzymatch. + */ +#ifdef WIZARD + if (wizard && !strcmp(o_str, "beartrap")) + return !strncmpi(o_str, u_str, 8); +#endif + /* ignore spaces & hyphens and upper/lower case when comparing */ if (fuzzymatch(u_str, o_str, " -", TRUE)) return TRUE; @@ -1659,7 +1728,8 @@ (void)mungspaces(bp); /* allow wishing for "nothing" to preserve wishless conduct... [now requires "wand of nothing" if that's what was really wanted] */ - if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil")) return no_wish; + if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") || + !strcmpi(bp, "none")) return no_wish; /* save the [nearly] unmodified choice string */ Strcpy(fruitbuf, bp); @@ -1902,6 +1972,9 @@ } as++; } + /* can't use spellings list for this one due to shuffling */ + if (!strcmpi(bp, "grey spellbook")) + *(bp + 2) = 'a'; } /* dragon scales - assumes order of dragons */ @@ -2015,6 +2088,8 @@ oclass = GEM_CLASS; dn = actualn = bp; goto srch; + } else if (!strcmpi(bp, "looking glass")) { + ; /* avoid false hit on "* glass" */ } else if (!BSTRCMPI(bp, p-6, " glass") || !strcmpi(bp, "glass")) { register char *g = bp; if (strstri(g, "broken")) return (struct obj *)0; @@ -2027,7 +2102,7 @@ typ = LAST_GEM + rnd(9); if (objects[typ].oc_class == GEM_CLASS) goto typfnd; else typ = 0; /* somebody changed objects[]? punt */ - } else if (g > bp) { /* try to construct canonical form */ + } else { /* try to construct canonical form */ char tbuf[BUFSZ]; Strcpy(tbuf, "worthless piece of "); Strcat(tbuf, g); /* assume it starts with the color */ @@ -2615,6 +2690,17 @@ return "cloak"; } +const char * +mimic_obj_name(mtmp) +struct monst *mtmp; +{ + if (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance != STRANGE_OBJECT) { + int idx = objects[mtmp->mappearance].oc_descr_idx; + if (mtmp->mappearance == GOLD_PIECE) return "gold"; + return obj_descr[idx].oc_name; + } + return "whatcha-may-callit"; +} #endif /* OVLB */ /*objnam.c*/ diff -Naurd ../nethack-3.4.0/src/options.c ./src/options.c --- ../nethack-3.4.0/src/options.c Wed Mar 20 23:43:12 2002 +++ ./src/options.c Mon Feb 24 15:25:05 2003 @@ -17,6 +17,12 @@ #define WINTYPELEN 16 +#ifdef DEFAULT_WC_TILED_MAP +#define PREFER_TILED TRUE +#else +#define PREFER_TILED FALSE +#endif + /* * NOTE: If you add (or delete) an option, please update the short * options help (option_help()), the long options help (dat/opthelp), @@ -38,7 +44,7 @@ #else {"altmeta", (boolean *)0, TRUE, DISP_IN_GAME}, #endif - {"ascii_map", &iflags.wc_ascii_map, TRUE, SET_IN_GAME}, /*WC*/ + {"ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME}, /*WC*/ #ifdef MFLOPPY {"asksavedisk", &flags.asksavedisk, FALSE, SET_IN_GAME}, #else @@ -62,7 +68,8 @@ #else {"checkspace", (boolean *)0, FALSE, SET_IN_FILE}, #endif -# ifdef MICRO + {"cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME}, +# if defined(MICRO) || defined(WIN32) {"color", &iflags.wc_color,TRUE, SET_IN_GAME}, /*WC*/ # else /* systems that support multiple terminals, many monochrome */ {"color", &iflags.wc_color, FALSE, SET_IN_GAME}, /*WC*/ @@ -103,9 +110,10 @@ #else {"ignintr", (boolean *)0, FALSE, SET_IN_FILE}, #endif - {"large_font", &iflags.wc_large_font, FALSE, SET_IN_FILE}, /*WC*/ + {"large_font", &iflags.obsolete, FALSE, SET_IN_FILE}, /* OBSOLETE */ {"legacy", &flags.legacy, TRUE, DISP_IN_GAME}, {"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME}, + {"lootabc", &iflags.lootabc, FALSE, SET_IN_GAME}, #ifdef MAC_GRAPHICS_ENV {"Macgraphics", &iflags.MACgraphics, TRUE, SET_IN_GAME}, #else @@ -122,11 +130,7 @@ #else {"menu_tab_sep", (boolean *)0, FALSE, SET_IN_FILE}, #endif -#ifdef TTY_GRAPHICS - {"msg_window", &iflags.prevmsg_window, FALSE, SET_IN_GAME}, -#else - {"msg_window", (boolean *)0, FALSE, SET_IN_FILE}, -#endif + {"mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME}, /*WC*/ #ifdef NEWS {"news", &iflags.news, TRUE, DISP_IN_GAME}, #else @@ -144,7 +148,7 @@ {"prayconfirm", &flags.prayconfirm, TRUE, SET_IN_GAME}, {"preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME}, /*WC*/ {"pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME}, -#if defined(MICRO) && !defined(AMIGA) && !defined(MSWIN_GRAPHICS) +#if defined(MICRO) && !defined(AMIGA) {"rawio", &iflags.rawio, FALSE, DISP_IN_GAME}, #else {"rawio", (boolean *)0, FALSE, SET_IN_FILE}, @@ -161,6 +165,7 @@ #else {"showexp", (boolean *)0, FALSE, SET_IN_FILE}, #endif + {"showrace", &iflags.showrace, FALSE, SET_IN_GAME}, #ifdef SCORE_ON_BOTL {"showscore", &flags.showscore, FALSE, SET_IN_GAME}, #else @@ -172,7 +177,7 @@ {"sparkle", &flags.sparkle, TRUE, SET_IN_GAME}, {"standout", &flags.standout, FALSE, SET_IN_GAME}, {"splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME}, /*WC*/ - {"tiled_map", &iflags.wc_tiled_map, FALSE, DISP_IN_GAME}, /*WC*/ + {"tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME}, /*WC*/ {"time", &flags.time, FALSE, SET_IN_GAME}, #ifdef TIMED_DELAY {"timed_delay", &flags.nap, TRUE, SET_IN_GAME}, @@ -181,6 +186,7 @@ #endif {"tombstone",&flags.tombstone, TRUE, SET_IN_GAME}, {"toptenwin",&flags.toptenwin, FALSE, SET_IN_GAME}, + {"travel", &iflags.travelcmd, TRUE, SET_IN_GAME}, {"use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME}, /*WC*/ {"verbose", &flags.verbose, TRUE, SET_IN_GAME}, {(char *)0, (boolean *)0, FALSE, 0} @@ -202,10 +208,6 @@ 8, DISP_IN_GAME }, { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/ { "align_status", "status window alignment", 20, DISP_IN_GAME }, /*WC*/ -#ifdef MAC - { "background", "the color of the background (black or white)", - 6, SET_IN_FILE }, -#endif { "boulder", "the symbol to use for displaying boulders", 1, SET_IN_GAME }, { "catname", "the name of your (first) cat (e.g., catname:Tabby)", @@ -258,6 +260,11 @@ MAXMCLASSES, SET_IN_FILE }, { "msghistory", "number of top line messages to save", 5, DISP_IN_GAME }, +# ifdef TTY_GRAPHICS + {"msg_window", "the type of message window required",1, SET_IN_GAME}, +# else + {"msg_window", "the type of message window required", 1, SET_IN_FILE}, +# endif { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ, DISP_IN_GAME }, { "objects", "the symbols to use for objects", @@ -283,8 +290,12 @@ PL_CSIZ, DISP_IN_GAME }, { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ, DISP_IN_GAME }, + { "runmode", "display updating frequency when `running' or `travelling'", + sizeof "teleport", SET_IN_GAME }, { "scores", "the parts of the score list you wish to see", 32, SET_IN_GAME }, + { "scroll_amount", "scroll the map this amount when scroll_margin is reached", + 20, DISP_IN_GAME }, /*WC*/ { "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/ #ifdef MSDOS { "soundcard", "type of sound card to use", 20, SET_IN_FILE }, @@ -296,9 +307,6 @@ { "tile_file", "name of tile file", 70, DISP_IN_GAME}, /*WC*/ { "traps", "the symbols to use in drawing traps", MAXTCHARS+1, SET_IN_FILE }, -#ifdef MAC - {"use_stone", "use stone background patterns", 8, SET_IN_FILE }, -#endif { "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/ #ifdef MSDOS { "video", "method of video updating", 20, SET_IN_FILE }, @@ -332,7 +340,7 @@ #endif static char def_inv_order[MAXOCLASSES] = { - GOLD_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS, + COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS, SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS, TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0, }; @@ -478,7 +486,11 @@ flags.end_own = FALSE; flags.end_top = 3; flags.end_around = 2; + iflags.runmode = RUN_LEAP; iflags.msg_history = 20; +#ifdef TTY_GRAPHICS + iflags.prevmsg_window = 's'; +#endif /* Use negative indices to indicate not yet selected */ flags.initrole = -1; @@ -516,7 +528,7 @@ * config file/environment variable below. */ /* this detects the IBM-compatible console on most 386 boxes */ - if (!strncmp(nh_getenv("TERM"), "AT", 2)) { + if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) { switch_graphics(IBM_GRAPHICS); # ifdef TEXTCOLOR iflags.use_color = TRUE; @@ -526,7 +538,8 @@ #if defined(UNIX) || defined(VMS) # ifdef TTY_GRAPHICS /* detect whether a "vt" terminal can handle alternate charsets */ - if (!strncmpi(nh_getenv("TERM"), "vt", 2) && (AS && AE) && + if ((opts = nh_getenv("TERM")) && + !strncmpi(opts, "vt", 2) && AS && AE && index(AS, '\016') && index(AE, '\017')) { switch_graphics(DEC_GRAPHICS); } @@ -744,7 +757,7 @@ num = 0; #ifndef GOLDOBJ if (!index(op, GOLD_SYM)) - buf[num++] = GOLD_CLASS; + buf[num++] = COIN_CLASS; #else /* !!!! probably unnecessary with gold as normal inventory */ #endif @@ -820,7 +833,7 @@ { int i; for (i = 0; i < WARNCOUNT; i++) - warnsyms[i] = graph_chars[i]; + if (graph_chars[i]) warnsyms[i] = graph_chars[i]; } STATIC_OVL int @@ -1018,7 +1031,7 @@ preferred_pet = 'n'; break; default: - pline("Unrecognized pet type '%s'", op); + pline("Unrecognized pet type '%s'.", op); break; } } else if (negated) preferred_pet = 'n'; @@ -1049,6 +1062,25 @@ return; } + fullname = "runmode"; + if (match_optname(opts, fullname, 4, TRUE)) { + if (negated) { + iflags.runmode = RUN_TPORT; + } else if ((op = string_for_opt(opts, FALSE)) != 0) { + if (!strncmpi(op, "teleport", strlen(op))) + iflags.runmode = RUN_TPORT; + else if (!strncmpi(op, "run", strlen(op))) + iflags.runmode = RUN_LEAP; + else if (!strncmpi(op, "walk", strlen(op))) + iflags.runmode = RUN_STEP; + else if (!strncmpi(op, "crawl", strlen(op))) + iflags.runmode = RUN_CRAWL; + else + badoption(opts); + } + return; + } + fullname = "msghistory"; if (match_optname(opts, fullname, 3, TRUE)) { op = string_for_env_opt(fullname, opts, negated); @@ -1058,6 +1090,41 @@ return; } + fullname="msg_window"; + /* msg_window:single, combo, full or reversed */ + if (match_optname(opts, fullname, 4, TRUE)) { + /* allow option to be silently ignored by non-tty ports */ +#ifdef TTY_GRAPHICS + int tmp; + if (!(op = string_for_opt(opts, TRUE))) { + tmp = negated ? 's' : 'f'; + } else { + if (negated) { + bad_negation(fullname, TRUE); + return; + } + tmp = tolower(*op); + } + switch (tmp) { + case 's': /* single message history cycle (default if negated) */ + iflags.prevmsg_window = 's'; + break; + case 'c': /* combination: two singles, then full page reversed */ + iflags.prevmsg_window = 'c'; + break; + case 'f': /* full page (default if no opts) */ + iflags.prevmsg_window = 'f'; + break; + case 'r': /* full page (reversed) */ + iflags.prevmsg_window = 'r'; + break; + default: + badoption(opts); + } +#endif + return; + } + /* WINCAP * setting font options */ fullname = "font"; @@ -1131,30 +1198,6 @@ return; } #ifdef CHANGE_COLOR -#ifdef MAC - fullname = "use_stone"; - if (match_optname(opts, fullname, 6, TRUE)) { - op = string_for_env_opt(fullname, opts, negated); - if ((negated && !op) || (!negated && op)) { - iflags.use_stone = negated ? 0 : atoi(op); - } else if (negated) bad_negation(fullname, TRUE); - return; - } - - fullname = "background"; - if (match_optname(opts, fullname, 5,TRUE)) - { - if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) - { - if (!strncmpi (op, "white", 5)) - change_background (1); - else if (!strncmpi (op, "black", 5)) - change_background (0); - } - return; - } -#endif - if (match_optname(opts, "palette", 3, TRUE) # ifdef MAC || match_optname(opts, "hicolor", 3, TRUE) @@ -1827,6 +1870,16 @@ return; } /* WINCAP + * scroll_amount:nn */ + fullname = "scroll_amount"; + if (match_optname(opts, fullname, sizeof("scroll_amount")-1, TRUE)) { + op = string_for_opt(opts, negated); + if ((negated && !op) || (!negated && op)) { + iflags.wc_scroll_amount = negated ? 1 : atoi(op); + } else if (negated) bad_negation(fullname, TRUE); + return; + } + /* WINCAP * scroll_margin:nn */ fullname = "scroll_margin"; if (match_optname(opts, fullname, sizeof("scroll_margin")-1, TRUE)) { @@ -2065,10 +2118,9 @@ vision_recalc(2); /* shut down vision */ vision_full_recalc = 1; /* delayed recalc */ } - else if ((boolopt[i].addr) == &iflags.use_inverse) { - need_redraw = TRUE; - } - else if ((boolopt[i].addr) == &iflags.hilite_pet) { + else if ((boolopt[i].addr) == &iflags.use_inverse || + (boolopt[i].addr) == &iflags.showrace || + (boolopt[i].addr) == &iflags.hilite_pet) { need_redraw = TRUE; } #ifdef TEXTCOLOR @@ -2104,6 +2156,9 @@ "strained", "overtaxed", "overloaded" }; +static NEARDATA const char *runmodes[] = { + "teleport", "run", "walk", "crawl" +}; /* * Convert the given string of object classes to a string of default object @@ -2133,7 +2188,7 @@ char from_ch, to_ch; { if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS) - pline("out of menu map space"); + pline("out of menu map space."); else { mapped_menu_cmds[n_menu_mapped] = from_ch; mapped_menu_op[n_menu_mapped] = to_ch; @@ -2160,7 +2215,7 @@ } -#if defined(MICRO) || defined(MAC) +#if defined(MICRO) || defined(MAC) || defined(WIN32) # define OPTIONS_HEADING "OPTIONS" #else # define OPTIONS_HEADING "NETHACKOPTIONS" @@ -2225,7 +2280,7 @@ start_menu(tmpwin); any.a_void = 0; - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Booleans (selecting will toggle value):", MENU_UNSELECTED); any.a_int = 0; /* first list any other non-modifiable booleans, then modifiable ones */ @@ -2257,7 +2312,7 @@ indexoffset = boolcount; any.a_void = 0; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Compounds (selecting will prompt for new value):", MENU_UNSELECTED); @@ -2298,7 +2353,7 @@ } #ifdef PREFIXES_IN_USE add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Variable playground locations:", MENU_UNSELECTED); for (i = 0; i < PREFIX_COUNT; i++) doset_add_menu(tmpwin, fqn_prefix_names[i], 0); @@ -2329,6 +2384,8 @@ setinitial, fromfile)) { Sprintf(buf, "Set %s to what?", compopt[opt_indx].name); getlin(buf, buf2); + if (buf2[0] == '\033') + continue; Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2); /* pass the buck */ parseoptions(buf, setinitial, fromfile); @@ -2358,7 +2415,8 @@ char buf[BUFSZ]; boolean retval = FALSE; - /* Special handling of menustyle, pickup_burden, and pickup_types, disclose options. */ + /* Special handling of menustyle, pickup_burden, and pickup_types, + disclose, runmode, and msg_window options. */ if (!strcmp("menustyle", optname)) { const char *style_name; menu_item *style_pick = (menu_item *)0; @@ -2465,6 +2523,82 @@ } } retval = TRUE; + } else if (!strcmp("runmode", optname)) { + const char *mode_name; + menu_item *mode_pick = (menu_item *)0; + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + for (i = 0; i < SIZE(runmodes); i++) { + mode_name = runmodes[i]; + any.a_int = i + 1; + add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0, + ATR_NONE, mode_name, MENU_UNSELECTED); + } + end_menu(tmpwin, "Select run/travel display mode:"); + if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) { + iflags.runmode = mode_pick->item.a_int - 1; + free((genericptr_t)mode_pick); + } + destroy_nhwindow(tmpwin); + retval = TRUE; + } +#ifdef TTY_GRAPHICS + else if (!strcmp("msg_window", optname)) { + /* by Christian W. Cooper */ + menu_item *window_pick = (menu_item *)0; + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + any.a_char = 's'; + add_menu(tmpwin, NO_GLYPH, &any, 's', 0, + ATR_NONE, "single", MENU_UNSELECTED); + any.a_char = 'c'; + add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, + ATR_NONE, "combination", MENU_UNSELECTED); + any.a_char = 'f'; + add_menu(tmpwin, NO_GLYPH, &any, 'f', 0, + ATR_NONE, "full", MENU_UNSELECTED); + any.a_char = 'r'; + add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, + ATR_NONE, "reversed", MENU_UNSELECTED); + end_menu(tmpwin, "Select message history display type:"); + if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) { + iflags.prevmsg_window = window_pick->item.a_char; + free((genericptr_t)window_pick); + } + destroy_nhwindow(tmpwin); + retval = TRUE; + } +#endif + else if (!strcmp("align_message", optname) || + !strcmp("align_status", optname)) { + menu_item *window_pick = (menu_item *)0; + char abuf[BUFSZ]; + boolean msg = (*(optname+6) == 'm'); + + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + any.a_int = ALIGN_TOP; + add_menu(tmpwin, NO_GLYPH, &any, 't', 0, + ATR_NONE, "top", MENU_UNSELECTED); + any.a_int = ALIGN_BOTTOM; + add_menu(tmpwin, NO_GLYPH, &any, 'b', 0, + ATR_NONE, "bottom", MENU_UNSELECTED); + any.a_int = ALIGN_LEFT; + add_menu(tmpwin, NO_GLYPH, &any, 'l', 0, + ATR_NONE, "left", MENU_UNSELECTED); + any.a_int = ALIGN_RIGHT; + add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, + ATR_NONE, "right", MENU_UNSELECTED); + Sprintf(abuf, "Select %s window placement relative to the map:", + msg ? "message" : "status"); + end_menu(tmpwin, abuf); + if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) { + if (msg) iflags.wc_align_message = window_pick->item.a_int; + else iflags.wc_align_status = window_pick->item.a_int; + free((genericptr_t)window_pick); + } + destroy_nhwindow(tmpwin); + retval = TRUE; } return retval; } @@ -2602,6 +2736,12 @@ Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "msghistory")) Sprintf(buf, "%u", iflags.msg_history); +#ifdef TTY_GRAPHICS + else if (!strcmp(optname, "msg_window")) + Sprintf(buf, "%s", (iflags.prevmsg_window=='s') ? "single" : + (iflags.prevmsg_window=='c') ? "combination" : + (iflags.prevmsg_window=='f') ? "full" : "reversed"); +#endif else if (!strcmp(optname, "name")) Sprintf(buf, "%s", plname); else if (!strcmp(optname, "objects")) @@ -2628,10 +2768,16 @@ Sprintf(buf, "%s", rolestring(flags.initrace, races, noun)); else if (!strcmp(optname, "role")) Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m)); + else if (!strcmp(optname, "runmode")) + Sprintf(buf, "%s", runmodes[iflags.runmode]); else if (!strcmp(optname, "scores")) { Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around, flags.end_own ? "/own" : ""); } + else if (!strcmp(optname, "scroll_amount")) { + if (iflags.wc_scroll_amount) Sprintf(buf, "%d",iflags.wc_scroll_amount); + else Strcpy(buf, defopt); + } else if (!strcmp(optname, "scroll_margin")) { if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin); else Strcpy(buf, defopt); @@ -3018,8 +3164,8 @@ {"color", WC_COLOR}, {"eight_bit_tty", WC_EIGHT_BIT_IN}, {"hilite_pet", WC_HILITE_PET}, - {"large_font", WC_LARGE_FONT}, /* now obsolete */ {"popup_dialog", WC_POPUP_DIALOG}, + {"player_selection", WC_PLAYER_SELECTION}, {"preload_tiles", WC_PRELOAD_TILES}, {"tiled_map", WC_TILED_MAP}, {"tile_file", WC_TILE_FILE}, @@ -3042,8 +3188,12 @@ {"font_status", WC_FONT_STATUS}, {"font_text", WC_FONT_TEXT}, {"map_mode", WC_MAP_MODE}, + {"scroll_amount", WC_SCROLL_AMOUNT}, {"scroll_margin", WC_SCROLL_MARGIN}, + {"splash_screen", WC_SPLASH_SCREEN}, {"vary_msgcount",WC_VARY_MSGCOUNT}, + {"windowcolors", WC_WINDOWCOLORS}, + {"mouse_support", WC_MOUSE_SUPPORT}, {(char *)0, 0L} }; @@ -3057,12 +3207,13 @@ */ void set_option_mod_status(optnam, status) -char *optnam; +const char *optnam; int status; { int k; if (status < SET_IN_FILE || status > SET_IN_GAME) { - impossible("set_option_mod_status: status out of range %d.", status); + impossible("set_option_mod_status: status out of range %d.", + status); return; } for (k = 0; boolopt[k].name; k++) { @@ -3094,7 +3245,8 @@ { int k = 0; if (status < SET_IN_FILE || status > SET_IN_GAME) { - impossible("set_option_mod_status: status out of range %d.", status); + impossible("set_option_mod_status: status out of range %d.", + status); return; } while (wc_options[k].wc_name) { @@ -3177,8 +3329,8 @@ int j; char buf[BUFSZ]; char *wn, *tfg, *tbg, *newop; - static char *wnames[] = {"menu", "message", "status", "text"}; - static char *shortnames[] = {"mnu", "msg", "sts", "txt"}; + static const char *wnames[] = { "menu", "message", "status", "text" }; + static const char *shortnames[] = { "mnu", "msg", "sts", "txt" }; static char **fgp[] = { &iflags.wc_foregrnd_menu, &iflags.wc_foregrnd_message, diff -Naurd ../nethack-3.4.0/src/pager.c ./src/pager.c --- ../nethack-3.4.0/src/pager.c Wed Mar 20 23:43:13 2002 +++ ./src/pager.c Mon Feb 24 15:25:05 2003 @@ -65,7 +65,7 @@ buf[0] = monbuf[0] = 0; glyph = glyph_at(x,y); - if (u.ux == x && u.uy == y && canseeself()) { + if (u.ux == x && u.uy == y && senseself()) { char race[QBUFSZ]; /* if not polymorphed, show both the role and the race */ @@ -79,6 +79,11 @@ race, mons[u.umonnum].mname, plname); + /* file lookup can't distinguish between "gnomish wizard" monster + and correspondingly named player character, always picking the + former; force it to find the general "wizard" entry instead */ + if (Role_if(PM_WIZARD) && Race_if(PM_GNOME) && !Upolyd) + pm = &mons[PM_WIZARD]; #ifdef STEED if (u.usteed) { @@ -89,6 +94,27 @@ Strcat(buf, steedbuf); } #endif + /* When you see yourself normally, no explanation is appended + (even if you could also see yourself via other means). + Sensing self while blind or swallowed is treated as if it + were by normal vision (cf canseeself()). */ + if ((Invisible || u.uundetected) && !Blind && !u.uswallow) { + unsigned how = 0; + + if (Infravision) how |= 1; + if (Unblind_telepat) how |= 2; + if (Detect_monsters) how |= 4; + + if (how) + Sprintf(eos(buf), " [seen: %s%s%s%s%s]", + (how & 1) ? "infravision" : "", + /* add comma if telep and infrav */ + ((how & 3) > 2) ? ", " : "", + (how & 2) ? "telepathy" : "", + /* add comma if detect and (infrav or telep or both) */ + ((how & 7) > 4) ? ", " : "", + (how & 4) ? "monster detection" : ""); + } } else if (u.uswallow) { /* all locations when swallowed other than the hero are the monster */ Sprintf(buf, "interior of %s", @@ -121,6 +147,18 @@ if (mtmp->mleashed) Strcat(buf, ", leashed to you"); + if (mtmp->mtrapped && cansee(mtmp->mx, mtmp->my)) { + struct trap *t = t_at(mtmp->mx, mtmp->my); + int tt = t ? t->ttyp : NO_TRAP; + + /* newsym lets you know of the trap, so mention it here */ + if (tt == BEAR_TRAP || tt == PIT || + tt == SPIKED_PIT ||tt == WEB) { + Strcat(buf, ", trapped in "); + Strcat(buf, defsyms[trap_to_defsym(tt)].explanation); + } + } + { int ways_seen = 0, normal = 0, xraydist; boolean useemon = (boolean) canseemon(mtmp); @@ -200,7 +238,7 @@ if (!otmp || otmp->otyp != glyph_to_obj(glyph)) { if (glyph_to_obj(glyph) != STRANGE_OBJECT) { otmp = mksobj(glyph_to_obj(glyph), FALSE, FALSE); - if (otmp->oclass == GOLD_CLASS) + if (otmp->oclass == COIN_CLASS) otmp->quan = 2L; /* to force pluralization */ else if (otmp->otyp == SLIME_MOLD) otmp->spe = current_fruit; /* give the fruit a type */ @@ -431,7 +469,7 @@ boolean from_screen; /* question from the screen */ boolean need_to_look; /* need to get explan. from glyph */ boolean hit_trap; /* true if found trap explanation */ - int skipped_venom = 0; /* non-zero if we ignored "splash of venom" */ + int skipped_venom; /* non-zero if we ignored "splash of venom" */ static const char *mon_interior = "the interior of a monster"; if (quick) { @@ -468,6 +506,7 @@ /* Reset some variables. */ need_to_look = FALSE; pm = (struct permonst *)0; + skipped_venom = 0; found = 0; out_str[0] = '\0'; @@ -521,7 +560,8 @@ /* Check for monsters */ for (i = 0; i < MAXMCLASSES; i++) { - if (sym == (from_screen ? monsyms[i] : def_monsyms[i])) { + if (sym == (from_screen ? monsyms[i] : def_monsyms[i]) && + monexplain[i]) { need_to_look = TRUE; if (!found) { Sprintf(out_str, "%c %s", sym, an(monexplain[i])); @@ -532,11 +572,14 @@ } } } - /* handle '@' as a special case; firstmatch is guaranteed - to already be set in that case */ - if (!from_screen ? (sym == def_monsyms[S_HUMAN]) : - (cc.x == u.ux && cc.y == u.uy && sym == monsyms[S_HUMAN])) - found += append_str(out_str, "you"); /* tack on "or you" */ + /* handle '@' as a special case if it refers to you and you're + playing a character which isn't normally displayed by that + symbol; firstmatch is assumed to already be set for '@' */ + if ((from_screen ? + (sym == monsyms[S_HUMAN] && cc.x == u.ux && cc.y == u.uy) : + (sym == def_monsyms[S_HUMAN] && !iflags.showrace)) && + !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd) + found += append_str(out_str, "you"); /* tack on "or you" */ /* * Special case: if identifying from the screen, and we're swallowed, @@ -629,6 +672,10 @@ } else { found += append_str(out_str, def_warnsyms[i].explanation); } + /* Kludge: warning trumps boulders on the display. + Reveal the boulder too or player can get confused */ + if (sobj_at(BOULDER, cc.x, cc.y)) + Strcat(out_str, " co-located with a boulder"); break; /* out of for loop*/ } } @@ -646,8 +693,15 @@ } /* handle optional boulder symbol as a special case */ - if (iflags.bouldersym && sym == iflags.bouldersym) + if (iflags.bouldersym && sym == iflags.bouldersym) { + if (!found) { + firstmatch = "boulder"; + Sprintf(out_str, "%c %s", sym, an(firstmatch)); + found++; + } else { found += append_str(out_str, "boulder"); + } + } /* * If we are looking at the screen, follow multiple possibilities or @@ -711,7 +765,7 @@ register struct trap *trap; int x, y, tt; - if (!getdir((char *)0)) return 0; + if (!getdir("^")) return 0; x = u.ux + u.dx; y = u.uy + u.dy; for (trap = ftrap; trap; trap = trap->ntrap) @@ -737,12 +791,14 @@ return 0; } -int -dowhatdoes() +char * +dowhatdoes_core(q, cbuf) +char q; +char *cbuf; { dlb *fp; - char bufr[BUFSZ+6]; - register char *buf = &bufr[6], *ep, q, ctrl, meta; + char bufr[BUFSZ]; + register char *buf = &bufr[6], *ep, ctrl, meta; fp = dlb_fopen(CMDHELPFILE, "r"); if (!fp) { @@ -750,16 +806,9 @@ return 0; } -#if defined(UNIX) || defined(VMS) - introff(); -#endif - q = yn_function("What command?", (char *)0, '\0'); -#if defined(UNIX) || defined(VMS) - intron(); -#endif - ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0); + ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0); meta = ((0x80 & q) ? (0x7f & q) : 0); - while(dlb_fgets(buf,BUFSZ,fp)) + while(dlb_fgets(buf,BUFSZ-6,fp)) { if ((ctrl && *buf=='^' && *(buf+1)==ctrl) || (meta && *buf=='M' && *(buf+1)=='-' && *(buf+2)==meta) || *buf==q) { @@ -778,12 +827,33 @@ buf[0] = q; (void) strncpy(buf+1, " ", 7); } - pline("%s", buf); (void) dlb_fclose(fp); - return 0; + Strcpy(cbuf, buf); + return cbuf; } - pline("I've never heard of such commands."); + } (void) dlb_fclose(fp); + return (char *)0; +} + +int +dowhatdoes() +{ + char bufr[BUFSZ]; + char q, *reslt; + +#if defined(UNIX) || defined(VMS) + introff(); +#endif + q = yn_function("What command?", (char *)0, '\0'); +#if defined(UNIX) || defined(VMS) + intron(); +#endif + reslt = dowhatdoes_core(q, bufr); + if (reslt) + pline("%s", reslt); + else + pline("I've never heard of such commands."); return 0; } diff -Naurd ../nethack-3.4.0/src/pickup.c ./src/pickup.c --- ../nethack-3.4.0/src/pickup.c Wed Mar 20 23:43:13 2002 +++ ./src/pickup.c Mon Feb 24 15:25:05 2003 @@ -32,7 +32,7 @@ STATIC_PTR int FDECL(ck_bag,(struct obj *)); STATIC_PTR int FDECL(out_container,(struct obj *)); STATIC_DCL int FDECL(menu_loot, (int, struct obj *, BOOLEAN_P)); -STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *)); +STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P)); STATIC_DCL boolean FDECL(able_to_loot, (int, int)); STATIC_DCL boolean FDECL(mon_beside, (int, int)); @@ -87,32 +87,36 @@ #ifndef GOLDOBJ int -collect_obj_classes(ilets, otmp, here, incl_gold, filter) +collect_obj_classes(ilets, otmp, here, incl_gold, filter, itemcount) char ilets[]; register struct obj *otmp; boolean here, incl_gold; boolean FDECL((*filter),(OBJ_P)); +int *itemcount; #else int -collect_obj_classes(ilets, otmp, here, filter) +collect_obj_classes(ilets, otmp, here, filter, itemcount) char ilets[]; register struct obj *otmp; boolean here; boolean FDECL((*filter),(OBJ_P)); +int *itemcount; #endif { register int iletct = 0; register char c; + *itemcount = 0; #ifndef GOLDOBJ if (incl_gold) - ilets[iletct++] = def_oc_syms[GOLD_CLASS]; + ilets[iletct++] = def_oc_syms[COIN_CLASS]; #endif ilets[iletct] = '\0'; /* terminate ilets so that index() will work */ while (otmp) { c = def_oc_syms[(int)otmp->oclass]; if (!index(ilets, c) && (!filter || (*filter)(otmp))) ilets[iletct++] = c, ilets[iletct] = '\0'; + *itemcount += 1; otmp = here ? otmp->nexthere : otmp->nobj; } @@ -158,6 +162,7 @@ boolean not_everything; char qbuf[QBUFSZ]; boolean m_seen; + int itemcount; oclasses[oclassct = 0] = '\0'; *one_at_a_time = *everything = m_seen = FALSE; @@ -165,12 +170,17 @@ #ifndef GOLDOBJ incl_gold, #endif - (boolean FDECL((*),(OBJ_P))) 0); + (boolean FDECL((*),(OBJ_P))) 0, &itemcount); if (iletct == 0) { return FALSE; } else if (iletct == 1) { oclasses[0] = def_char_to_objclass(ilets[0]); oclasses[1] = '\0'; + if (itemcount && menu_on_demand) { + ilets[iletct++] = 'm'; + *menu_on_demand = 0; + ilets[iletct] = '\0'; + } } else { /* more than one choice available */ const char *where = 0; register char sym, oc_of_sym, *p; @@ -312,20 +322,21 @@ allow_category(obj) struct obj *obj; { + if (Role_if(PM_PRIEST)) obj->bknown = TRUE; if (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) || (index(valid_menu_classes, obj->oclass) != (char *)0)) return TRUE; else if (((index(valid_menu_classes,'U') != (char *)0) && - (obj->oclass != GOLD_CLASS && obj->bknown && !obj->blessed && !obj->cursed))) + (obj->oclass != COIN_CLASS && obj->bknown && !obj->blessed && !obj->cursed))) return TRUE; else if (((index(valid_menu_classes,'B') != (char *)0) && - (obj->oclass != GOLD_CLASS && obj->bknown && obj->blessed))) + (obj->oclass != COIN_CLASS && obj->bknown && obj->blessed))) return TRUE; else if (((index(valid_menu_classes,'C') != (char *)0) && - (obj->oclass != GOLD_CLASS && obj->bknown && obj->cursed))) + (obj->oclass != COIN_CLASS && obj->bknown && obj->cursed))) return TRUE; else if (((index(valid_menu_classes,'X') != (char *)0) && - (obj->oclass != GOLD_CLASS && !obj->bknown))) + (obj->oclass != COIN_CLASS && !obj->bknown))) return TRUE; else return FALSE; @@ -437,9 +448,9 @@ goto menu_pickup; } - if (flags.menu_style != MENU_TRADITIONAL) { - /* use menus exclusively */ + if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) { + /* use menus exclusively */ if (count) { /* looking for N of something */ char buf[QBUFSZ]; Sprintf(buf, "Pick %d of what?", count); @@ -524,7 +535,7 @@ continue; if (!all_of_a_type) { - char qbuf[QBUFSZ]; + char qbuf[BUFSZ]; Sprintf(qbuf, "Pick up %s?", doname(obj)); switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) { case 'q': goto end_query; /* out 2 levels */ @@ -905,15 +916,15 @@ } /* could we carry `obj'? if not, could we carry some of it/them? */ -STATIC_OVL -long carry_count(obj, container, count, telekinesis, wt_before, wt_after) +STATIC_OVL long +carry_count(obj, container, count, telekinesis, wt_before, wt_after) struct obj *obj, *container; /* object to pick up, bag it's coming out of */ long count; boolean telekinesis; int *wt_before, *wt_after; { boolean adjust_wt = container && carried(container), - is_gold = obj->oclass == GOLD_CLASS; + is_gold = obj->oclass == COIN_CLASS; int wt, iw, ow, oow; long qq, savequan; #ifdef GOLDOBJ @@ -1090,7 +1101,7 @@ if (*cnt_p < 1L) { result = -1; /* nothing lifted */ #ifndef GOLDOBJ - } else if (obj->oclass != GOLD_CLASS && inv_cnt() >= 52 && + } else if (obj->oclass != COIN_CLASS && inv_cnt() >= 52 && !merge_choice(invent, obj)) { #else } else if (inv_cnt() >= 52 && !merge_choice(invent, obj)) { @@ -1107,7 +1118,7 @@ if (telekinesis) { result = 0; /* don't lift */ } else { - char qbuf[QBUFSZ]; + char qbuf[BUFSZ]; long savequan = obj->quan; obj->quan = *cnt_p; @@ -1121,6 +1132,7 @@ case 'n': result = 0; break; default: break; /* 'y' => result == 1 */ } + clear_nhwindow(WIN_MESSAGE); } } } @@ -1166,7 +1178,7 @@ } else if (obj->oartifact && !touch_artifact(obj,&youmonst)) { return 0; #ifndef GOLDOBJ - } else if (obj->oclass == GOLD_CLASS) { + } else if (obj->oclass == COIN_CLASS) { /* Special consideration for gold pieces... */ long iw = (long)max_capacity() - GOLD_WT(u.ugold); long gold_capacity = GOLD_CAPACITY(iw, u.ugold); @@ -1247,7 +1259,7 @@ #ifdef GOLDOBJ /* Whats left of the special case for gold :-) */ - if (obj->oclass == GOLD_CLASS) flags.botl = 1; + if (obj->oclass == COIN_CLASS) flags.botl = 1; #endif if (obj->quan != count && obj->otyp != LOADSTONE) obj = splitobj(obj, count); @@ -1275,10 +1287,7 @@ struct obj *otmp; { obj_extract_self(otmp); - if (otmp->no_charge) { - /* this attribute only applies to objects outside invent */ - otmp->no_charge = 0; - } else if (otmp != uball && costly_spot(otmp->ox, otmp->oy)) { + if (otmp != uball && costly_spot(otmp->ox, otmp->oy)) { char saveushops[5], fakeshop[2]; /* addtobill cares about your location rather than the object's; @@ -1295,6 +1304,8 @@ if (!index(u.ushops, *fakeshop)) remote_burglary(otmp->ox, otmp->oy); } + if (otmp->no_charge) /* only applies to objects outside invent */ + otmp->no_charge = 0; if (Invisible) newsym(otmp->ox, otmp->oy); return addinv(otmp); /* might merge it with other objects */ } @@ -1368,8 +1379,7 @@ if (!can_reach_floor()) { #ifdef STEED if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) - You("aren't skilled enough to reach from %s.", - mon_nam(u.usteed)); + rider_cant_reach(); /* not skilled enough to reach */ else #endif You("cannot reach the %s.", surface(x, y)); @@ -1386,8 +1396,8 @@ return TRUE; } -STATIC_OVL -boolean mon_beside(x,y) +STATIC_OVL boolean +mon_beside(x,y) int x, y; { int i,j,nx,ny; @@ -1402,16 +1412,16 @@ } int -doloot() /* loot a container on the floor. */ +doloot() /* loot a container on the floor or loot saddle from mon. */ { register struct obj *cobj, *nobj; register int c = -1; int timepassed = 0; - int x,y; + coord cc; boolean underfoot = TRUE; const char *dont_find_anything = "don't find anything"; struct monst *mtmp; - char qbuf[QBUFSZ]; + char qbuf[BUFSZ]; int prev_inquiry = 0; boolean prev_loot = FALSE; @@ -1423,13 +1433,15 @@ You("have no hands!"); /* not `body_part(HAND)' */ return 0; } - x = u.ux; y = u.uy; + cc.x = u.ux; cc.y = u.uy; lootcont: - if (container_at(x, y, FALSE)) { - if (!able_to_loot(x, y)) return 0; - for (cobj = level.objects[x][y]; cobj; cobj = nobj) { + if (container_at(cc.x, cc.y, FALSE)) { + boolean any = FALSE; + + if (!able_to_loot(cc.x, cc.y)) return 0; + for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) { nobj = cobj->nexthere; if (Is_container(cobj)) { @@ -1437,6 +1449,7 @@ c = ynq(qbuf); if (c == 'q') return (timepassed); if (c == 'n') continue; + any = TRUE; if (cobj->olocked) { pline("Hmmm, it seems to be locked."); @@ -1459,6 +1472,7 @@ if (multi < 0) return 1; /* chest trap */ } } + if (any) c = 'y'; } else if (Confusion) { #ifndef GOLDOBJ if (u.ugold){ @@ -1468,7 +1482,7 @@ struct obj *goldob; /* Find a money object to mess with */ for (goldob = invent; goldob; goldob = goldob->nobj) { - if (goldob->oclass == GOLD_CLASS) break; + if (goldob->oclass == COIN_CLASS) break; } if (goldob){ long contribution = rnd((int)min(LARGEST_INT, goldob->quan)); @@ -1516,32 +1530,28 @@ pline("Ok, now there is loot here."); } } - } else if (IS_GRAVE(levl[x][y].typ)) { + } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) { You("need to dig up the grave to effectively loot it..."); } /* * 3.3.1 introduced directional looting for some things. */ if (c != 'y' && mon_beside(u.ux, u.uy)) { - if (!getdir("Loot in what direction?")) { - pline(Never_mind); - return(0); - } - x = u.ux + u.dx; - y = u.uy + u.dy; - if (x == u.ux && y == u.uy) { + if (!get_adjacent_loc("Loot in what direction?", "Invalid loot location", + u.ux, u.uy, &cc)) return 0; + if (cc.x == u.ux && cc.y == u.uy) { underfoot = TRUE; - if (container_at(x, y, FALSE)) + if (container_at(cc.x, cc.y, FALSE)) goto lootcont; } else underfoot = FALSE; if (u.dz < 0) { You("%s to loot on the %s.", dont_find_anything, - ceiling(x, y)); + ceiling(cc.x, cc.y)); timepassed = 1; return timepassed; } - mtmp = m_at(x, y); + mtmp = m_at(cc.x, cc.y); if (mtmp) timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot); /* Preserve pre-3.3.1 behaviour for containers. @@ -1549,7 +1559,7 @@ * from one square away to change that in the future. */ if (!underfoot) { - if (container_at(x, y, FALSE)) { + if (container_at(cc.x, cc.y, FALSE)) { if (mtmp) { You_cant("loot anything %sthere with %s in the way.", prev_inquiry ? "else " : "", mon_nam(mtmp)); @@ -1609,7 +1619,7 @@ if ((unwornmask = otmp->owornmask) != 0L) { mtmp->misc_worn_check &= ~unwornmask; otmp->owornmask = 0L; - update_mon_intrinsics(mtmp, otmp, FALSE); + update_mon_intrinsics(mtmp, otmp, FALSE, FALSE); } otmp = hold_another_object(otmp, "You drop %s!", doname(otmp), (const char *)0); @@ -1665,8 +1675,8 @@ in_container(obj) register struct obj *obj; { - boolean is_gold = (obj->oclass == GOLD_CLASS); boolean floor_container = !carried(current_container); + boolean was_unpaid = FALSE; char buf[BUFSZ]; if (!current_container) { @@ -1751,9 +1761,16 @@ (void) snuff_lit(obj); if (floor_container && costly_spot(u.ux, u.uy)) { + if (current_container->no_charge && !obj->unpaid) { + /* don't sell when putting the item into your own container */ + obj->no_charge = 1; + } else { + /* sellobj() will take an unpaid item off the shop bill */ + was_unpaid = obj->unpaid ? TRUE : FALSE; sellobj_state(SELL_DELIBERATE); sellobj(obj, u.ux, u.uy); sellobj_state(SELL_NORMAL); + } } if (Icebox && obj->otyp != OIL_LAMP && obj->otyp != BRASS_LANTERN && !Is_candle(obj)) { @@ -1764,21 +1781,11 @@ (void) stop_timer(REVIVE_MON, (genericptr_t)obj); /* mark a non-reviving corpse as such */ if (rot_alarm) obj->norevive = 1; - } - } - - else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) { - You("are blasted by a magical explosion!"); - - /* the !floor_container case is taken care of */ - if(*u.ushops && costly_spot(u.ux, u.uy) && floor_container) { - register struct monst *shkp; - - if ((shkp = shop_keeper(*u.ushops)) != 0) - (void)stolen_value(current_container, u.ux, u.uy, - (boolean)shkp->mpeaceful, FALSE); } + } else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) { + You("are blasted by a magical explosion!"); /* did not actually insert obj yet */ + if (was_unpaid) addtobill(obj, FALSE, FALSE, TRUE); obfree(obj, (struct obj *)0); delete_contents(current_container); if (!floor_container) @@ -1799,7 +1806,11 @@ (void) add_to_container(current_container, obj); current_container->owt = weight(current_container); } - if (is_gold) bot(); /* update gold piece count immediately */ + /* gold needs this, and freeinv() many lines above may cause + * the encumbrance to disappear from the status, so just always + * update status immediately. + */ + bot(); return(current_container ? 1 : -1); } @@ -1817,7 +1828,7 @@ register struct obj *obj; { register struct obj *otmp; - boolean is_gold = (obj->oclass == GOLD_CLASS); + boolean is_gold = (obj->oclass == COIN_CLASS); int res, loadlev; long count; @@ -1865,15 +1876,14 @@ } /* simulated point of time */ - if (is_pick(obj) && !obj->unpaid && *u.ushops && shop_keeper(*u.ushops)) - verbalize("You sneaky cad! Get out of here with that pick!"); if(!obj->unpaid && !carried(current_container) && costly_spot(current_container->ox, current_container->oy)) { - obj->ox = current_container->ox; obj->oy = current_container->oy; addtobill(obj, FALSE, FALSE, FALSE); } + if (is_pick(obj) && !obj->unpaid && *u.ushops && shop_keeper(*u.ushops)) + verbalize("You sneaky cad! Get out of here with that pick!"); otmp = addinv(obj); loadlev = near_capacity(); @@ -1906,11 +1916,19 @@ struct monst *shkp; boolean one_by_one, allflag, loot_out = FALSE, loot_in = FALSE; char select[MAXOCLASSES+1]; - char qbuf[QBUFSZ]; + char qbuf[BUFSZ], emptymsg[BUFSZ], pbuf[QBUFSZ]; long loss = 0L; int cnt = 0, used = 0, lcnt = 0, menu_on_request; + emptymsg[0] = '\0'; + if (nohands(youmonst.data)) { + You("have no hands!"); /* not `body_part(HAND)' */ + return 0; + } else if (!freehand()) { + You("have no free %s.", body_part(HAND)); + return 0; + } if (obj->olocked) { pline("%s to be locked.", Tobjnam(obj, "seem")); if (held) You("must put it down to unlock."); @@ -1992,20 +2010,31 @@ } } - if (cnt && loss) + if (lcnt && loss) You("owe %ld %s for lost item%s.", loss, currency(loss), lcnt > 1 ? "s" : ""); obj->owt = weight(obj); - if (!cnt) { - pline("%s %s empty.", Yname2(obj), otense(obj, "are")); - } else { + if (!cnt) Sprintf(emptymsg, "%s %s empty.", Yname2(obj), otense(obj, "are")); + if (cnt || flags.menu_style == MENU_FULL) { Sprintf(qbuf, "Do you want to take %s out of %s?", something, yname(obj)); if (flags.menu_style != MENU_TRADITIONAL) { if (flags.menu_style == MENU_FULL) { - int t = in_or_out_menu("Do what?", current_container); + int t; + char menuprompt[BUFSZ]; + boolean outokay = (cnt != 0); + boolean inokay = (invent != 0); + if (!outokay && !inokay) { + pline("%s", emptymsg); + pline("You don't have anything to put in."); + return used; + } + menuprompt[0] = '\0'; + if (!cnt) Sprintf(menuprompt, "%s ", emptymsg); + Strcat(menuprompt, "Do what?"); + t = in_or_out_menu(menuprompt, current_container, outokay, inokay); if (t <= 0) return 0; loot_out = (t & 0x01) != 0; loot_in = (t & 0x02) != 0; @@ -2021,7 +2050,9 @@ ask_again2: menu_on_request = 0; add_valid_menu_class(0); /* reset */ - switch (yn_function(qbuf, ":ynq", 'n')) { + Strcpy(pbuf, ":ynq"); + if (cnt) Strcat(pbuf, "m"); + switch (yn_function(qbuf, pbuf, 'n')) { case ':': container_contents(current_container, FALSE, FALSE); goto ask_again2; @@ -2046,11 +2077,17 @@ /*FALLTHRU*/ case 'n': break; + case 'm': + menu_on_request = -2; /* triggers ALL_CLASSES */ + used |= menu_loot(menu_on_request, current_container, FALSE) > 0; + break; case 'q': default: return used; } } + } else { + pline("%s", emptymsg); /* is empty. */ } #ifndef GOLDOBJ @@ -2062,9 +2099,26 @@ You("don't have anything to put in."); return used; } - if (flags.menu_style != MENU_FULL || !cnt) { - loot_in = (yn_function("Do you wish to put something in?", - ynqchars, 'n') == 'y'); + if (flags.menu_style != MENU_FULL) { + Sprintf(qbuf, "Do you wish to put %s in?", something); + Strcpy(pbuf, ynqchars); + if (flags.menu_style == MENU_TRADITIONAL && invent && inv_cnt() > 0) + Strcat(pbuf, "m"); + switch (yn_function(qbuf, pbuf, 'n')) { + case 'y': + loot_in = TRUE; + break; + case 'n': + break; + case 'm': + add_valid_menu_class(0); /* reset */ + menu_on_request = -2; /* triggers ALL_CLASSES */ + used |= menu_loot(menu_on_request, current_container, TRUE) > 0; + break; + case 'q': + default: + return used; + } } /* * Gone: being nice about only selecting food if we know we are @@ -2078,6 +2132,7 @@ * and put it at the head of the inventory list. */ u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */ + u_gold->in_use = TRUE; u.ugold = u_gold->quan; /* put the gold back */ assigninvlet(u_gold); /* might end up as NOINVSYM */ u_gold->nobj = invent; @@ -2108,10 +2163,11 @@ } #ifndef GOLDOBJ - if (u_gold && invent && invent->oclass == GOLD_CLASS) { + if (u_gold && invent && invent->oclass == COIN_CLASS) { /* didn't stash [all of] it */ u_gold = invent; invent = u_gold->nobj; + u_gold->in_use = FALSE; dealloc_obj(u_gold); } #endif @@ -2178,8 +2234,13 @@ /* special split case also handled by askchain() */ } res = put_in ? in_container(otmp) : out_container(otmp); - if (res < 0) + if (res < 0) { + if (otmp != pick_list[i].item.a_obj) { + /* split occurred, merge again */ + (void) merged(&pick_list[i].item.a_obj, &otmp); + } break; + } } free((genericptr_t)pick_list); } @@ -2188,28 +2249,39 @@ } STATIC_OVL int -in_or_out_menu(prompt, obj) +in_or_out_menu(prompt, obj, outokay, inokay) const char *prompt; struct obj *obj; +boolean outokay, inokay; { winid win; anything any; menu_item *pick_list; char buf[BUFSZ]; int n; + const char *menuselector = iflags.lootabc ? "abc" : "oib"; any.a_void = 0; win = create_nhwindow(NHW_MENU); start_menu(win); - any.a_int = 1; - Sprintf(buf,"Take %s out of %s", something, the(xname(obj))); - add_menu(win, NO_GLYPH, &any, 'o', 0, ATR_NONE, buf, MENU_UNSELECTED); - any.a_int = 2; - Sprintf(buf,"Put %s into %s", something, the(xname(obj))); - add_menu(win, NO_GLYPH, &any, 'i', 0, ATR_NONE, buf, MENU_UNSELECTED); - any.a_int = 3; - add_menu(win, NO_GLYPH, &any, 'b', 0, ATR_NONE, - "Both of the above", MENU_UNSELECTED); + if (outokay) { + any.a_int = 1; + Sprintf(buf,"Take %s out of %s", something, the(xname(obj))); + add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, + buf, MENU_UNSELECTED); + } + menuselector++; + if (inokay) { + any.a_int = 2; + Sprintf(buf,"Put %s into %s", something, the(xname(obj))); + add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, buf, MENU_UNSELECTED); + } + menuselector++; + if (outokay && inokay) { + any.a_int = 3; + add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, + "Both of the above", MENU_UNSELECTED); + } end_menu(win, prompt); n = select_menu(win, PICK_ONE, &pick_list); destroy_nhwindow(win); diff -Naurd ../nethack-3.4.0/src/pline.c ./src/pline.c --- ../nethack-3.4.0/src/pline.c Wed Mar 20 23:43:13 2002 +++ ./src/pline.c Mon Feb 24 15:25:05 2003 @@ -248,6 +248,11 @@ impossible VA_DECL(const char *, s) VA_START(s); VA_INIT(s, const char *); + { + char pbuf[BUFSZ]; + Vsprintf(pbuf,s,VA_ARGS); + paniclog("impossible", pbuf); + } vpline(s,VA_ARGS); pline("Program in disorder - perhaps you'd better #quit."); VA_END(); diff -Naurd ../nethack-3.4.0/src/polyself.c ./src/polyself.c --- ../nethack-3.4.0/src/polyself.c Wed Mar 20 23:43:13 2002 +++ ./src/polyself.c Mon Feb 24 15:25:05 2003 @@ -33,8 +33,8 @@ const char *fmt, *arg; { boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow, - was_mimicking_gold = (youmonst.m_ap_type == M_AP_OBJECT - && youmonst.mappearance == GOLD_PIECE); + was_mimicking = (youmonst.m_ap_type == M_AP_OBJECT); + boolean was_blind = !!Blind; if (Upolyd) { @@ -52,7 +52,7 @@ if (sticky) uunstick(); find_ac(); - if (was_mimicking_gold) { + if (was_mimicking) { if (multi < 0) unmul(""); } else { /* @@ -83,6 +83,10 @@ } done(GENOCIDED); } + + if (u.twoweap && !could_twoweap(youmonst.data)) + untwoweapon(); + if (was_blind && !Blind) { /* reverting from eyeless */ Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ @@ -155,7 +159,7 @@ reset_rndmonst(NON_PM); /* new monster generation criteria */ /* random experience points for the new experience level */ - u.uexp = rndexp(); + u.uexp = rndexp(FALSE); /* u.uhpmax * u.ulevel / oldlvl: proportionate hit points to new level * -10 and +10: don't apply proportionate HP to 10 of a starting @@ -302,7 +306,7 @@ /* The below polyok() fails either if everything is genocided, or if * we deliberately chose something illegal to force newman(). */ - if (!polyok(&mons[mntmp]) || !rn2(5)) + if (!polyok(&mons[mntmp]) || !rn2(5) || your_race(&mons[mntmp])) newman(); else if(!polymon(mntmp)) return; @@ -352,10 +356,12 @@ flags.female = u.mfemale; } - if (youmonst.m_ap_type == M_AP_OBJECT && - youmonst.mappearance == GOLD_PIECE) { - /* stop mimicking gold immediately */ + if (youmonst.m_ap_type) { + /* stop mimicking immediately */ if (multi < 0) unmul(""); + } else if (mons[mntmp].mlet != S_MIMIC) { + /* as in polyman() */ + youmonst.m_ap_type = M_AP_NOTHING; } if (is_male(&mons[mntmp])) { if(flags.female) dochange = TRUE; @@ -583,7 +589,7 @@ } #endif } else if (sliparm(youmonst.data)) { - if ((otmp = uarm) != 0) { + if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) { if (donning(otmp)) cancel_don(); Your("armor falls around you!"); (void) Armor_gone(); @@ -606,6 +612,23 @@ } #endif } + if (has_horns(youmonst.data)) { + if ((otmp = uarmh) != 0) { + if (is_flimsy(otmp) && !donning(otmp)) { + char hornbuf[BUFSZ], yourbuf[BUFSZ]; + + /* Future possiblities: This could damage/destroy helmet */ + Sprintf(hornbuf, "horn%s", plur(num_horns(youmonst.data))); + Your("%s through %s %s.", vtense(hornbuf, "pierce"), + shk_your(yourbuf, otmp), xname(otmp)); + } else { + if (donning(otmp)) cancel_don(); + Your("helmet falls to the %s!", surface(u.ux, u.uy)); + (void) Helmet_off(); + dropx(otmp); + } + } + } if (nohands(youmonst.data) || verysmall(youmonst.data)) { if ((otmp = uarmg) != 0) { if (donning(otmp)) cancel_don(); @@ -668,6 +691,8 @@ dropx(otmp2); } untwoweapon(); + } else if (!could_twoweap(youmonst.data)) { + untwoweapon(); } } } @@ -705,6 +730,8 @@ int dobreathe() { + struct attack *mattk; + if (Strangled) { You_cant("breathe. Sorry."); return(0); @@ -717,17 +744,13 @@ flags.botl = 1; if (!getdir((char *)0)) return(0); - else { - register struct attack *mattk; - register int i; - for(i = 0; i < NATTK; i++) { - mattk = &(youmonst.data->mattk[i]); - if(mattk->aatyp == AT_BREA) break; - } + mattk = attacktype_fordmg(youmonst.data, AT_BREA, AD_ANY); + if (!mattk) + impossible("bad breath attack?"); /* mouthwash needed... */ + else buzz((int) (20 + mattk->adtyp-1), (int)mattk->damn, u.ux, u.uy, u.dx, u.dy); - } return(1); } @@ -998,8 +1021,7 @@ /* as if gazing at a sleeping anything is fruitful... */ You("turn to stone..."); killer_format = KILLED_BY; - killer = - "deliberately gazing at Medusa's hideous countenance"; + killer = "deliberately meeting Medusa's gaze"; done(STONING); } } @@ -1109,6 +1131,10 @@ "rear claw", "foreclaw", "clawed", "head", "rear limb", "light headed", "neck", "spine", "rear claw tip", "fur", "blood", "lung", "nose", "stomach" }, + *bird_parts[] = { "wing", "eye", "face", "wing", "wing tip", + "foot", "wing", "winged", "head", "leg", + "light headed", "neck", "spine", "toe", + "feathers", "blood", "lung", "bill", "stomach" }, *horse_parts[] = { "foreleg", "eye", "face", "forehoof", "hoof tip", "rear hoof", "foreclaw", "hooved", "head", "rear leg", "light headed", "neck", "backbone", "rear hoof tip", @@ -1169,9 +1195,17 @@ (part == ARM || part == FINGER || part == FINGERTIP || part == HAND || part == HANDED)) return humanoid_parts[part]; + if (mptr == &mons[PM_RAVEN]) + return bird_parts[part]; if (mptr->mlet == S_CENTAUR || mptr->mlet == S_UNICORN || (mptr == &mons[PM_ROTHE] && part != HAIR)) return horse_parts[part]; + if (mptr->mlet == S_LIGHT) { + if (part == HANDED) return "rayed"; + else if (part == ARM || part == FINGER || + part == FINGERTIP || part == HAND) return "ray"; + else return "beam"; + } if (mptr->mlet == S_EEL && mptr != &mons[PM_JELLYFISH]) return fish_parts[part]; if (slithy(mptr) || (mptr->mlet == S_DRAGON && part == HAIR)) @@ -1225,7 +1259,7 @@ if (u.umonnum != PM_FLESH_GOLEM && u.umonnum != PM_IRON_GOLEM) return; switch (damtype) { - case AD_ELEC: if (u.umonnum == PM_IRON_GOLEM) + case AD_ELEC: if (u.umonnum == PM_FLESH_GOLEM) heal = dam / 6; /* Approx 1 per die */ break; case AD_FIRE: if (u.umonnum == PM_IRON_GOLEM) diff -Naurd ../nethack-3.4.0/src/potion.c ./src/potion.c --- ../nethack-3.4.0/src/potion.c Wed Mar 20 23:43:14 2002 +++ ./src/potion.c Mon Feb 24 15:25:05 2003 @@ -152,11 +152,13 @@ long old = Vomiting; if(!xtime && old) - if(talk) You_feel("much less nauseous now."); + if(talk) You_feel("much less nauseated now."); set_itimeout(&Vomiting, xtime); } +static const char vismsg[] = "vision seems to %s for a moment but is %s now."; +static const char eyemsg[] = "%s momentarily %s."; void make_blinded(xtime, talk) @@ -167,9 +169,6 @@ boolean u_could_see, can_see_now; int eyecnt; char buf[BUFSZ]; - static const char - vismsg[] = "vision seems to %s for a moment but is %s now.", - eyemsg[] = "%s momentarily %s."; /* we need to probe ahead in case the Eyes of the Overworld are or will be overriding blindness */ @@ -245,17 +244,13 @@ boolean talk; long mask; /* nonzero if resistance status should change by mask */ { + long old = HHallucination; boolean changed = 0; -#ifdef LINT - const char *message = 0; -#else - const char *message; -#endif + const char *message, *verb; - if (!xtime) - message = "Everything looks SO boring now."; - else - message = "Oh wow! Everything seems so cosmic!"; + message = (!xtime) ? "Everything %s SO boring now." : + "Oh wow! Everything %s so cosmic!"; + verb = (!Blind) ? "looks" : "feels"; if (mask) { if (HHallucination) changed = TRUE; @@ -266,6 +261,22 @@ if (!EHalluc_resistance && (!!HHallucination != !!xtime)) changed = TRUE; set_itimeout(&HHallucination, xtime); + + /* clearing temporary hallucination without toggling vision */ + if (!changed && !HHallucination && old && talk) { + if (!haseyes(youmonst.data)) { + strange_feeling((struct obj *)0, (char *)0); + } else if (Blind) { + char buf[BUFSZ]; + int eyecnt = eyecount(youmonst.data); + + Strcpy(buf, body_part(EYE)); + Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf), + (eyecnt == 1) ? "itches" : "itch"); + } else { /* Grayswandir */ + Your(vismsg, "flatten", "normal"); + } + } } if (changed) { @@ -277,8 +288,13 @@ see_objects(); see_traps(); } + + /* for perm_inv and anything similar + (eg. Qt windowport's equipped items display) */ + update_inventory(); + flags.botl = 1; - if (!Blind && talk) pline(message); + if (talk) pline(message, verb); } } @@ -303,8 +319,11 @@ nomovemsg = "You regain your composure."; } +/* "Quaffing is like drinking, except you spill more." -- Terry Pratchett + */ int -dodrink() { +dodrink() +{ register struct obj *otmp; const char *potion_descr; @@ -368,6 +387,7 @@ { int retval; + otmp->in_use = TRUE; nothing = unkn = 0; if((retval = peffects(otmp)) >= 0) return(retval); @@ -539,10 +559,12 @@ if (otmp->cursed) pline("Yecch! This tastes %s.", Hallucination ? "overripe" : "rotten"); - else pline(Hallucination ? - "This tastes like 10%% real %s%s juice all-natural beverage." : - "This tastes like %s%s juice.", - otmp->odiluted ? "reconstituted " : "", pl_fruit); + else + pline(Hallucination ? + "This tastes like 10%% real %s%s all-natural beverage." : + "This tastes like %s%s.", + otmp->odiluted ? "reconstituted " : "", + fruitname(TRUE)); if (otmp->otyp == POT_FRUIT_JUICE) { u.uhunger += (otmp->odiluted ? 5 : 10) * (2 + bcsign(otmp)); newuhs(FALSE); @@ -571,7 +593,7 @@ if (Free_action) You("stiffen momentarily."); else { - if (Levitation||Is_airlevel(&u.uz)||Is_waterlevel(&u.uz)) + if (Levitation || Is_airlevel(&u.uz)||Is_waterlevel(&u.uz)) You("are motionlessly suspended."); #ifdef STEED else if (u.usteed) @@ -632,8 +654,8 @@ case POT_SICKNESS: pline("Yecch! This stuff tastes like poison."); if (otmp->blessed) { - pline("(But in fact it was mildly stale %s juice.)", - pl_fruit); + pline("(But in fact it was mildly stale %s.)", + fruitname(TRUE)); if (!Role_if(PM_HEALER)) { if (otmp->corpsenm) losehp(1, @@ -645,8 +667,8 @@ } else { if(Poison_resistance) pline( - "(But in fact it was biologically contaminated %s juice.)", - pl_fruit); + "(But in fact it was biologically contaminated %s.)", + fruitname(TRUE)); if (Role_if(PM_HEALER)) pline("Fortunately, you have been immunized."); else { @@ -763,7 +785,7 @@ /* blessed potions place you at a random spot in the * middle of the new level instead of the low point */ - u.uexp = rndexp(); + u.uexp = rndexp(TRUE); break; case POT_HEALING: You_feel("better."); @@ -1428,6 +1450,7 @@ /* KMH -- Water into acid causes an explosion */ if (obj->otyp == POT_ACID) { pline("It boils vigorously!"); + You("are caught in the explosion!"); losehp(rnd(10), "elementary chemistry", KILLED_BY); makeknown(obj->otyp); update_inventory(); @@ -1480,7 +1503,7 @@ } else { if (!Blind) { boolean oq1 = obj->quan == 1L; - pline_The("spellbook%s fade%s.", + pline_The("spellbook%s %s.", oq1 ? "" : "s", otense(obj, "fade")); } if(obj->unpaid && costly_spot(u.ux, u.uy)) { @@ -1523,9 +1546,14 @@ tmp = (here == POOL) ? "pool" : "moat"; Sprintf(qbuf, "Dip it into the %s?", tmp); if (yn(qbuf) == 'y') { - if (Levitation) + if (Levitation) { floating_above(tmp); - else { +#ifdef STEED + } else if (u.usteed && !is_swimmer(u.usteed->data) && + P_SKILL(P_RIDING) < P_BASIC) { + rider_cant_reach(); /* not skilled enough to reach */ +#endif + } else { (void) get_wet(obj); if (obj->otyp == POT_ACID) useup(obj); } @@ -1539,6 +1567,7 @@ pline("That is a potion bottle, not a Klein bottle!"); return 0; } + potion->in_use = TRUE; /* assume it will be used up */ if(potion->otyp == POT_WATER) { boolean useeit = !Blind; if (useeit) (void) Shk_Your(Your_buf, obj); @@ -1548,7 +1577,7 @@ pline("%s %s %s.", Your_buf, aobjnam(obj, "softly glow"), - hcolor(amber)); + hcolor(NH_AMBER)); uncurse(obj); obj->bknown=1; poof: @@ -1559,7 +1588,7 @@ return(1); } else if(!obj->blessed) { if (useeit) { - tmp = hcolor(light_blue); + tmp = hcolor(NH_LIGHT_BLUE); pline("%s %s with a%s %s aura.", Your_buf, aobjnam(obj, "softly glow"), @@ -1581,7 +1610,7 @@ goto poof; } else if(!obj->cursed) { if (useeit) { - tmp = hcolor(Black); + tmp = hcolor(NH_BLACK); pline("%s %s with a%s %s aura.", Your_buf, aobjnam(obj, "glow"), @@ -1624,11 +1653,13 @@ makeknown(POT_POLYMORPH); useup(potion); prinv((char *)0, obj, 0L); + return 1; } else { pline("Nothing seems to happen."); - useup(potion); + goto poof; } } + potion->in_use = FALSE; /* didn't go poof */ return(1); } else if(obj->oclass == POTION_CLASS && obj->otyp != potion->otyp) { /* Mixing potions is dangerous... */ @@ -1813,6 +1844,7 @@ } if (obj->age > 1000L) { pline("%s %s full.", Yname2(obj), otense(obj, "are")); + potion->in_use = FALSE; /* didn't go poof */ } else { You("fill %s with oil.", yname(obj)); check_unpaid(potion); /* Yendorian Fuel Tax */ @@ -1827,9 +1859,20 @@ return 1; } + potion->in_use = FALSE; /* didn't go poof */ if ((obj->otyp == UNICORN_HORN || obj->otyp == AMETHYST) && (mixture = mixtype(obj, potion)) != 0) { + char oldbuf[BUFSZ], newbuf[BUFSZ]; + short old_otyp = potion->otyp; + boolean old_dknown = FALSE; boolean more_than_one = potion->quan > 1; + + oldbuf[0] = '\0'; + if (potion->dknown) { + old_dknown = TRUE; + Sprintf(oldbuf, "%s ", + hcolor(OBJ_DESCR(objects[potion->otyp]))); + } /* with multiple merged potions, split off one and just clear it */ if (potion->quan > 1L) { @@ -1847,24 +1890,29 @@ else singlepotion->cursed = obj->cursed; /* odiluted left as-is */ singlepotion->bknown = FALSE; - if (Blind) - singlepotion->dknown = FALSE; - else { - if (mixture == POT_WATER && -#ifdef DCC30_BUG - (singlepotion->dknown = !Hallucination, - singlepotion->dknown != 0)) -#else - (singlepotion->dknown = !Hallucination) != 0) -#endif - pline_The("potion%s clears.", - more_than_one ? " that you dipped into" : ""); - else - pline_The("potion%s turns %s.", - more_than_one ? " that you dipped into" : "", - hcolor(OBJ_DESCR(objects[mixture]))); + if (Blind) { + singlepotion->dknown = FALSE; + } else { + singlepotion->dknown = !Hallucination; + if (mixture == POT_WATER && singlepotion->dknown) + Sprintf(newbuf, "clears"); + else + Sprintf(newbuf, "turns %s", + hcolor(OBJ_DESCR(objects[mixture]))); + pline_The("%spotion%s %s.", oldbuf, + more_than_one ? " that you dipped into" : "", + newbuf); + if(!objects[old_otyp].oc_uname && + !objects[old_otyp].oc_name_known && old_dknown) { + struct obj fakeobj; + fakeobj = zeroobj; + fakeobj.dknown = 1; + fakeobj.otyp = old_otyp; + fakeobj.oclass = POTION_CLASS; + docall(&fakeobj); + } } - obj_extract_self(singlepotion); + obj_extract_self(singlepotion); singlepotion = hold_another_object(singlepotion, "You juggle and drop %s!", doname(singlepotion), (const char *)0); diff -Naurd ../nethack-3.4.0/src/pray.c ./src/pray.c --- ../nethack-3.4.0/src/pray.c Wed Mar 20 23:43:14 2002 +++ ./src/pray.c Mon Feb 24 15:25:05 2003 @@ -6,6 +6,7 @@ #include "epri.h" STATIC_PTR int NDECL(prayer_done); +STATIC_DCL struct obj *NDECL(worst_cursed_item); STATIC_DCL int NDECL(in_trouble); STATIC_DCL void FDECL(fix_worst_trouble,(int)); STATIC_DCL void FDECL(angrygods,(ALIGNTYP_P)); @@ -23,6 +24,9 @@ STATIC_DCL boolean FDECL(water_prayer,(BOOLEAN_P)); STATIC_DCL boolean FDECL(blocked_boulder,(int,int)); +/* simplify a few tests */ +#define Cursed_obj(obj,typ) ((obj) && (obj)->otyp == (typ) && (obj)->cursed) + /* * Logic behind deities and altars and such: * + prayers are made to your god if not on an altar, and to the altar's god @@ -59,6 +63,13 @@ #define FERVENT 9 #define STRIDENT 4 +/* + * The actual trouble priority is determined by the order of the + * checks performed in in_trouble() rather than by these numeric + * values, so keep that code and these values synchronized in + * order to have the values be meaningful. + */ + #define TROUBLE_STONED 12 #define TROUBLE_SLIMED 11 #define TROUBLE_STRANGLED 10 @@ -69,18 +80,20 @@ #define TROUBLE_LYCANTHROPE 5 #define TROUBLE_COLLAPSING 4 #define TROUBLE_STUCK_IN_WALL 3 -#define TROUBLE_CURSED_BLINDFOLD 2 -#define TROUBLE_CURSED_LEVITATION 1 +#define TROUBLE_CURSED_LEVITATION 2 +#define TROUBLE_CURSED_BLINDFOLD 1 #define TROUBLE_PUNISHED (-1) -#define TROUBLE_CURSED_ITEMS (-2) -#define TROUBLE_BLIND (-3) -#define TROUBLE_POISONED (-4) -#define TROUBLE_WOUNDED_LEGS (-5) -#define TROUBLE_HUNGRY (-6) -#define TROUBLE_STUNNED (-7) -#define TROUBLE_CONFUSED (-8) -#define TROUBLE_HALLUCINATION (-9) +#define TROUBLE_FUMBLING (-2) +#define TROUBLE_CURSED_ITEMS (-3) +#define TROUBLE_SADDLE (-4) +#define TROUBLE_BLIND (-5) +#define TROUBLE_POISONED (-6) +#define TROUBLE_WOUNDED_LEGS (-7) +#define TROUBLE_HUNGRY (-8) +#define TROUBLE_STUNNED (-9) +#define TROUBLE_CONFUSED (-10) +#define TROUBLE_HALLUCINATION (-11) /* We could force rehumanize of polyselfed people, but we can't tell unintentional shape changes from the other kind. Oh well. */ @@ -102,7 +115,9 @@ STATIC_OVL int in_trouble() { +#ifdef STEED register struct obj *otmp; +#endif int i, j, count=0; /* Borrowed from eat.c */ @@ -115,6 +130,9 @@ #define FAINTED 5 #define STARVED 6 + /* + * major troubles + */ if(Stoned) return(TROUBLE_STONED); if(Slimed) return(TROUBLE_SLIMED); if(Strangled) return(TROUBLE_STRANGLED); @@ -136,36 +154,28 @@ if (count == 8 && !Passes_walls) return(TROUBLE_STUCK_IN_WALL); - if((uarmf && uarmf->otyp==LEVITATION_BOOTS && uarmf->cursed) || - (uleft && uleft->otyp==RIN_LEVITATION && uleft->cursed) || - (uright && uright->otyp==RIN_LEVITATION && uright->cursed)) + if (Cursed_obj(uarmf, LEVITATION_BOOTS) || + stuck_ring(uleft, RIN_LEVITATION) || + stuck_ring(uright, RIN_LEVITATION)) return(TROUBLE_CURSED_LEVITATION); if(Blindfolded && ublindf->cursed) return(TROUBLE_CURSED_BLINDFOLD); + /* + * minor troubles + */ if(Punished) return(TROUBLE_PUNISHED); - for(otmp=invent; otmp; otmp=otmp->nobj) - if((otmp->otyp==LOADSTONE || otmp->otyp==LUCKSTONE) && - otmp->cursed) - return(TROUBLE_CURSED_ITEMS); - if((uarmh && uarmh->cursed) || /* helmet */ - (uarms && uarms->cursed) || /* shield */ - (uarmg && uarmg->cursed) || /* gloves */ - (uarm && uarm->cursed) || /* armor */ - (uarmc && uarmc->cursed) || /* cloak */ - (uarmf && uarmf->cursed && uarmf->otyp != LEVITATION_BOOTS) || - /* boots */ - (ublindf && ublindf->otyp == LENSES && ublindf->cursed) || - /* lenses: blindfold is TROUBLE_CURSED_BLINDFOLD */ -#ifdef TOURIST - (uarmu && uarmu->cursed) || /* shirt */ + if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING) || + Cursed_obj(uarmf, FUMBLE_BOOTS)) + return TROUBLE_FUMBLING; + if (worst_cursed_item()) return TROUBLE_CURSED_ITEMS; +#ifdef STEED + if (u.usteed) { /* can't voluntarily dismount from a cursed saddle */ + otmp = which_armor(u.usteed, W_SADDLE); + if (Cursed_obj(otmp, SADDLE)) return TROUBLE_SADDLE; + } #endif - (welded(uwep)) || - (uleft && uleft->cursed && uleft->otyp != RIN_LEVITATION) || - (uright && uright->cursed && uright->otyp != RIN_LEVITATION) || - (uamul && uamul->cursed)) - return(TROUBLE_CURSED_ITEMS); - if(Blinded > 1) return(TROUBLE_BLIND); + if (Blinded > 1 && haseyes(youmonst.data)) return(TROUBLE_BLIND); for(i=0; i= HVY_ENCUMBER) { + for (otmp = invent; otmp; otmp = otmp->nobj) + if (Cursed_obj(otmp, LOADSTONE)) return otmp; + } + /* weapon takes precedence if it is interfering + with taking off a ring or shield */ + if (welded(uwep) && /* weapon */ + (uright || (bimanual(uwep) && (uleft || uarms)))) { + otmp = uwep; + /* gloves come next, due to rings */ + } else if (uarmg && uarmg->cursed) { /* gloves */ + otmp = uarmg; + /* then shield due to two handed weapons and spells */ + } else if (uarms && uarms->cursed) { /* shield */ + otmp = uarms; + /* then cloak due to body armor */ + } else if (uarmc && uarmc->cursed) { /* cloak */ + otmp = uarmc; + } else if (uarm && uarm->cursed) { /* suit */ + otmp = uarm; + } else if (uarmh && uarmh->cursed) { /* helmet */ + otmp = uarmh; + } else if (uarmf && uarmf->cursed) { /* boots */ + otmp = uarmf; +#ifdef TOURIST + } else if (uarmu && uarmu->cursed) { /* shirt */ + otmp = uarmu; +#endif + } else if (uamul && uamul->cursed) { /* amulet */ + otmp = uamul; + } else if (uleft && uleft->cursed) { /* left ring */ + otmp = uleft; + } else if (uright && uright->cursed) { /* right ring */ + otmp = uright; + } else if (ublindf && ublindf->cursed) { /* eyewear */ + otmp = ublindf; /* must be non-blinding lenses */ + /* if weapon wasn't handled above, do it now */ + } else if (welded(uwep)) { /* weapon */ + otmp = uwep; + /* active secondary weapon even though it isn't welded */ + } else if (uswapwep && uswapwep->cursed && u.twoweap) { + otmp = uswapwep; + /* all worn items ought to be handled by now */ + } else { + for (otmp = invent; otmp; otmp = otmp->nobj) { + if (!otmp->cursed) continue; + if (otmp->otyp == LOADSTONE || confers_luck(otmp)) + break; + } + } + return otmp; +} STATIC_OVL void fix_worst_trouble(trouble) register int trouble; { int i; - struct obj *otmp; + struct obj *otmp = 0; const char *what = (const char *)0; + static NEARDATA const char leftglow[] = "left ring softly glows", + rightglow[] = "right ring softly glows"; switch (trouble) { case TROUBLE_STONED: @@ -219,7 +287,7 @@ /* teleport should always succeed, but if not, * just untrap them. */ - if(!safe_teleds()) + if(!safe_teleds(FALSE)) u.utrap = 0; break; case TROUBLE_STARVING: @@ -256,19 +324,15 @@ case TROUBLE_STUCK_IN_WALL: Your("surroundings change."); /* no control, but works on no-teleport levels */ - (void) safe_teleds(); + (void) safe_teleds(FALSE); break; case TROUBLE_CURSED_LEVITATION: - if (uarmf && uarmf->otyp==LEVITATION_BOOTS - && uarmf->cursed) + if (Cursed_obj(uarmf, LEVITATION_BOOTS)) { otmp = uarmf; - else if (uleft && uleft->otyp==RIN_LEVITATION - && uleft->cursed) { - otmp = uleft; - what = leftglow; - } else { - otmp = uright; - what = rightglow; + } else if ((otmp = stuck_ring(uleft,RIN_LEVITATION)) !=0) { + if (otmp == uleft) what = leftglow; + } else if ((otmp = stuck_ring(uright,RIN_LEVITATION))!=0) { + if (otmp == uright) what = rightglow; } goto decurse; case TROUBLE_CURSED_BLINDFOLD: @@ -277,67 +341,36 @@ case TROUBLE_LYCANTHROPE: you_unwere(TRUE); break; + /* + */ case TROUBLE_PUNISHED: Your("chain disappears."); unpunish(); break; + case TROUBLE_FUMBLING: + if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING)) + otmp = uarmg; + else if (Cursed_obj(uarmf, FUMBLE_BOOTS)) + otmp = uarmf; + goto decurse; + /*NOTREACHED*/ + break; case TROUBLE_CURSED_ITEMS: - /* weapon takes precedence if it interferes - with taking off a ring or shield */ - if (welded(uwep) && /* weapon */ - (uright || (bimanual(uwep) && (uleft || uarms)))) - otmp = uwep; - /* gloves come next, due to rings */ - else if (uarmg && uarmg->cursed) /* gloves */ - otmp = uarmg; - /* then shield due to two handed weapons and spells */ - else if (uarms && uarms->cursed) /* shield */ - otmp = uarms; - /* then cloak due to body armor */ - else if (uarmc && uarmc->cursed) /* cloak */ - otmp = uarmc; - else if (uarm && uarm->cursed) /* armor */ - otmp = uarm; - else if (uarmh && uarmh->cursed) /* helmet */ - otmp = uarmh; - else if (uarmf && uarmf->cursed) /* boots */ - otmp = uarmf; -#ifdef TOURIST - else if (uarmu && uarmu->cursed) /* shirt */ - otmp = uarmu; -#endif - /* (perhaps amulet should take precedence over rings?) */ - else if (uleft && uleft->cursed) { - otmp = uleft; - what = leftglow; - } else if (uright && uright->cursed) { - otmp = uright; - what = rightglow; - } else if (uamul && uamul->cursed) /* amulet */ - otmp = uamul; - else if (ublindf && ublindf->cursed) /* eyewear */ - otmp = ublindf; /* must be non-blinding lenses */ - /* if weapon wasn't handled above, do it now */ - else if (welded(uwep)) /* weapon */ - otmp = uwep; - else { - for(otmp=invent; otmp; otmp=otmp->nobj) - if ((otmp->otyp==LOADSTONE || - otmp->otyp==LUCKSTONE) && otmp->cursed) - break; - } + otmp = worst_cursed_item(); + if (otmp == uright) what = rightglow; + else if (otmp == uleft) what = leftglow; decurse: if (!otmp) { impossible("fix_worst_trouble: nothing to uncurse."); return; } uncurse(otmp); - otmp->bknown = TRUE; - if (!Blind) - Your("%s %s.", - what ? what : - (const char *)aobjnam(otmp, "softly glow"), - hcolor(amber)); + if (!Blind) { + Your("%s %s.", what ? what : + (const char *)aobjnam(otmp, "softly glow"), + hcolor(NH_AMBER)); + otmp->bknown = TRUE; + } update_inventory(); break; case TROUBLE_POISONED: @@ -354,14 +387,17 @@ (void) encumber_msg(); break; case TROUBLE_BLIND: - { - int num_eyes = eyecount(youmonst.data); - Your("%s feel%s better.", - (num_eyes == 1) ? body_part(EYE) : makeplural(body_part(EYE)), - (num_eyes == 1) ? "s" : ""); - make_blinded(0L,FALSE); - break; - } + { + int num_eyes = eyecount(youmonst.data); + const char *eye = body_part(EYE); + + Your("%s feel%s better.", + (num_eyes == 1) ? eye : makeplural(eye), + (num_eyes == 1) ? "s" : ""); + u.ucreamed = 0; + make_blinded(0L,FALSE); + break; + } case TROUBLE_WOUNDED_LEGS: heal_legs(); break; @@ -375,6 +411,19 @@ pline ("Looks like you are back in Kansas."); make_hallucinated(0L,FALSE,0L); break; +#ifdef STEED + case TROUBLE_SADDLE: + otmp = which_armor(u.usteed, W_SADDLE); + uncurse(otmp); + if (!Blind) { + pline("%s %s %s.", + s_suffix(upstart(y_monnam(u.usteed))), + aobjnam(otmp, "softly glow"), + hcolor(NH_AMBER)); + otmp->bknown = TRUE; + } + break; +#endif } } @@ -445,7 +494,7 @@ if (!Disint_resistance) fry_by_god(resp_god); else { - You("bask in its %s glow for a minute...", Black); + You("bask in its %s glow for a minute...", NH_BLACK); godvoice(resp_god, "I believe it not!"); } if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) { @@ -517,7 +566,7 @@ case 5: gods_angry(resp_god); if (!Blind && !Antimagic) pline("%s glow surrounds you.", - An(hcolor(Black))); + An(hcolor(NH_BLACK))); rndcurse(); break; case 7: @@ -664,7 +713,7 @@ { char swordbuf[BUFSZ]; - Sprintf(swordbuf, "%s sword", hcolor(Black)); + Sprintf(swordbuf, "%s sword", hcolor(NH_BLACK)); if (class_gift != STRANGE_OBJECT) { ; /* already got bonus above */ } else if (in_hand) { @@ -745,9 +794,9 @@ /* if hero was in trouble, but got better, no special favor */ if (p_trouble == 0) pat_on_head = 1; } else { - int action = rn1(on_altar() ? 3 + on_shrine() : 2, Luck+1); + int action = rn1(Luck + (on_altar() ? 3 + on_shrine() : 2), 1); - if (!on_altar()) action = max(action,2); + if (!on_altar()) action = min(action, 3); if (u.ualign.record < STRIDENT) action = (u.ualign.record > 0 || !rnl(2)) ? 1 : 0; @@ -767,6 +816,9 @@ } } + /* note: can't get pat_on_head unless all troubles have just been + fixed or there were no troubles to begin with; hallucination + won't be in effect so special handling for it is superfluous */ if(pat_on_head) switch(rn2((Luck + 6)>>1)) { case 0: break; @@ -785,7 +837,7 @@ uwep->bknown = TRUE; if (!Blind) Your("%s %s%s.", aobjnam(uwep, "softly glow"), - hcolor(amber), repair_buf); + hcolor(NH_AMBER), repair_buf); else You_feel("the power of %s over your %s.", u_gname(), xname(uwep)); *repair_buf = '\0'; @@ -795,7 +847,7 @@ if (!Blind) Your("%s with %s aura%s.", aobjnam(uwep, "softly glow"), - an(hcolor(light_blue)), repair_buf); + an(hcolor(NH_LIGHT_BLUE)), repair_buf); else You_feel("the blessing of %s over your %s.", u_gname(), xname(uwep)); *repair_buf = '\0'; @@ -816,8 +868,8 @@ break; case 3: /* takes 2 hints to get the music to enter the stronghold */ - if (flags.soundok && !u.uevent.uopened_dbridge) { - if(u.uevent.uheard_tune < 1) { + if (!u.uevent.uopened_dbridge) { + if (u.uevent.uheard_tune < 1) { godvoice(g_align,(char *)0); verbalize("Hark, %s!", youmonst.data->mlet == S_HUMAN ? "mortal" : "creature"); @@ -826,7 +878,7 @@ u.uevent.uheard_tune++; break; } else if (u.uevent.uheard_tune < 2) { - You_hear(Hallucination ? "a funeral march..." : "a divine music..."); + You_hear("a divine music..."); pline("It sounds like: \"%s\".", tune); u.uevent.uheard_tune++; break; @@ -835,7 +887,7 @@ /* Otherwise, falls into next case */ case 2: if (!Blind) - You("are surrounded by %s glow.", an(hcolor(golden))); + You("are surrounded by %s glow.", an(hcolor(NH_GOLDEN))); /* if any levels have been lost (and not yet regained), treat this effect like blessed full healing */ if (u.ulevel < u.ulevelmax) { @@ -860,13 +912,13 @@ if (Blind) You_feel("the power of %s.", u_gname()); else You("are surrounded by %s aura.", - an(hcolor(light_blue))); + an(hcolor(NH_LIGHT_BLUE))); for(otmp=invent; otmp; otmp=otmp->nobj) { if (otmp->cursed) { uncurse(otmp); if (!Blind) { Your("%s %s.", aobjnam(otmp, "softly glow"), - hcolor(amber)); + hcolor(NH_AMBER)); otmp->bknown = TRUE; ++any; } @@ -973,7 +1025,7 @@ ((other && changed > 1L) ? "Some of the" : (other ? "One of the" : "The")), ((other || changed > 1L) ? "s" : ""), (changed > 1L ? "" : "s"), - (bless_water ? hcolor(light_blue) : hcolor(Black))); + (bless_water ? hcolor(NH_LIGHT_BLUE) : hcolor(NH_BLACK))); } return((boolean)(changed > 0L)); } @@ -1045,7 +1097,7 @@ int pm; aligntyp altaralign = a_align(u.ux,u.uy); - if (!on_altar()) { + if (!on_altar() || u.uswallow) { You("are not standing on an altar."); return 0; } @@ -1109,7 +1161,7 @@ if (altaralign == A_CHAOTIC && u.ualign.type != A_CHAOTIC) { pline( "The blood floods the altar, which vanishes in %s cloud!", - an(hcolor(Black))); + an(hcolor(NH_BLACK))); levl[u.ux][u.uy].typ = ROOM; levl[u.ux][u.uy].altarmask = 0; if(Invisible) newsym(u.ux, u.uy); @@ -1311,8 +1363,8 @@ if (!Blind) pline_The("altar glows %s.", hcolor( - u.ualign.type == A_LAWFUL ? White : - u.ualign.type ? Black : (const char *)"gray")); + u.ualign.type == A_LAWFUL ? NH_WHITE : + u.ualign.type ? NH_BLACK : (const char *)"gray")); if (rnl(u.ulevel) > 6 && u.ualign.record > 0 && rnd(u.ualign.record) > (3*ALIGNLIM)/4) diff -Naurd ../nethack-3.4.0/src/priest.c ./src/priest.c --- ../nethack-3.4.0/src/priest.c Wed Mar 20 23:43:14 2002 +++ ./src/priest.c Mon Feb 24 15:25:05 2003 @@ -49,10 +49,7 @@ else allowflags = ALLOW_SSM | ALLOW_SANCT; if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL); if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; - if (tunnels(mtmp->data) && - (!needspick(mtmp->data) || m_carrying(mtmp, PICK_AXE) || - m_carrying(mtmp, DWARVISH_MATTOCK))) - allowflags |= ALLOW_DIG; + if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG; if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { allowflags |= OPENDOOR; if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; @@ -339,14 +336,22 @@ shrined = has_shrine(priest); sanctum = (priest->data == &mons[PM_HIGH_PRIEST] && (Is_sanctum(&u.uz) || In_endgame(&u.uz))); - can_speak = (priest->mcanmove && !priest->msleeping); - if (can_speak) + can_speak = (priest->mcanmove && !priest->msleeping && + flags.soundok); + if (can_speak) { + unsigned save_priest = priest->ispriest; + /* don't reveal the altar's owner upon temple entry in + the endgame; for the Sanctum, the next message names + Moloch so suppress the "of Moloch" for him here too */ + if (sanctum && !Hallucination) priest->ispriest = 0; pline("%s intones:", - (!Blind ? Monnam(priest) : "A nearby voice")); + canseemon(priest) ? Monnam(priest) : "A nearby voice"); + priest->ispriest = save_priest; + } msg2 = 0; if(sanctum && Is_sanctum(&u.uz)) { if(priest->mpeaceful) { - msg1 = "Infidel, you entered Moloch's Sanctum!"; + msg1 = "Infidel, you have entered Moloch's Sanctum!"; msg2 = "Be gone!"; priest->mpeaceful = 0; set_malign(priest); diff -Naurd ../nethack-3.4.0/src/quest.c ./src/quest.c --- ../nethack-3.4.0/src/quest.c Wed Mar 20 23:43:14 2002 +++ ./src/quest.c Mon Feb 24 15:25:05 2003 @@ -16,7 +16,7 @@ STATIC_DCL void NDECL(on_locate); STATIC_DCL void NDECL(on_goal); STATIC_DCL boolean NDECL(not_capable); -STATIC_DCL boolean FDECL(is_pure, (BOOLEAN_P)); +STATIC_DCL int FDECL(is_pure, (BOOLEAN_P)); STATIC_DCL void FDECL(expulsion, (BOOLEAN_P)); STATIC_DCL void NDECL(chat_with_leader); STATIC_DCL void NDECL(chat_with_nemesis); @@ -96,7 +96,7 @@ ok_to_quest() { return((boolean)((Qstat(got_quest) || Qstat(got_thanks))) - && is_pure(FALSE)); + && (is_pure(FALSE) > 0)); } STATIC_OVL boolean @@ -105,10 +105,11 @@ return((boolean)(u.ulevel < MIN_QUEST_LEVEL)); } -STATIC_OVL boolean +STATIC_OVL int is_pure(talk) boolean talk; { + int purity; aligntyp original_alignment = u.ualignbase[A_ORIGINAL]; #ifdef WIZARD @@ -126,9 +127,11 @@ } } #endif - return (boolean)(u.ualign.record >= MIN_QUEST_ALIGN && - u.ualign.type == original_alignment && - u.ualignbase[A_CURRENT] == original_alignment); + purity = (u.ualign.record >= MIN_QUEST_ALIGN && + u.ualign.type == original_alignment && + u.ualignbase[A_CURRENT] == original_alignment) ? 1 : + (u.ualignbase[A_CURRENT] != original_alignment) ? -1 : 0; + return purity; } /* @@ -245,7 +248,10 @@ qt_pager(QT_BADLEVEL); exercise(A_WIS, TRUE); expulsion(FALSE); - } else if(!is_pure(TRUE)) { + } else if(is_pure(TRUE) < 0) { + com_pager(QT_BANISHED); + expulsion(TRUE); + } else if(is_pure(TRUE) == 0) { qt_pager(QT_BADALIGN); if(Qstat(not_ready) == MAX_QUEST_TRIES) { qt_pager(QT_LASTLEADER); diff -Naurd ../nethack-3.4.0/src/read.c ./src/read.c --- ../nethack-3.4.0/src/read.c Wed Mar 20 23:43:15 2002 +++ ./src/read.c Mon Feb 24 15:25:05 2003 @@ -17,13 +17,6 @@ #ifdef OVLB -/* elven armor vibrates warningly when enchanted beyond a limit */ -#define is_elven_armor(optr) ((optr)->otyp == ELVEN_LEATHER_HELM\ - || (optr)->otyp == ELVEN_MITHRIL_COAT\ - || (optr)->otyp == ELVEN_CLOAK\ - || (optr)->otyp == ELVEN_SHIELD\ - || (optr)->otyp == ELVEN_BOOTS) - boolean known; static NEARDATA const char readable[] = @@ -127,11 +120,7 @@ if (scroll->otyp == SCR_MAIL) confused = FALSE; #endif if(scroll->oclass == SPBOOK_CLASS) { - if(confused) { - You("cannot grasp the meaning of this tome."); - return(0); - } else - return(study_book(scroll)); + return(study_book(scroll)); } scroll->in_use = TRUE; /* scroll, not spellbook, now being read */ if(scroll->otyp != SCR_BLANK_PAPER) { @@ -274,7 +263,7 @@ wand_explode(obj); return; } - if (obj->spe >= lim) p_glow2(obj,blue); + if (obj->spe >= lim) p_glow2(obj, NH_BLUE); else p_glow1(obj); } @@ -345,7 +334,7 @@ else obj->spe += n; } - p_glow2(obj,blue); + p_glow2(obj, NH_BLUE); } else { n = rn1(5,10); /* 5..15 */ if (obj->spe + n <= 50) @@ -357,7 +346,7 @@ else obj->spe += n; } - p_glow2(obj,White); + p_glow2(obj, NH_WHITE); } break; case OIL_LAMP: @@ -372,7 +361,7 @@ } else if (is_blessed) { obj->spe = 1; obj->age = 1500; - p_glow2(obj,blue); + p_glow2(obj, NH_BLUE); } else { obj->spe = 1; obj->age += 750; @@ -384,7 +373,7 @@ if (is_cursed) stripspe(obj); else if (is_blessed) { obj->spe = 6; - p_glow2(obj,blue); + p_glow2(obj, NH_BLUE); } else { if (obj->spe < 5) { obj->spe++; @@ -401,7 +390,7 @@ obj->spe += rn1(10, 6); else obj->spe += rn1(5, 6); if (obj->spe > 50) obj->spe = 50; - p_glow2(obj,blue); + p_glow2(obj, NH_BLUE); } else { obj->spe += rnd(5); if (obj->spe > 50) obj->spe = 50; @@ -418,7 +407,7 @@ } else if (is_blessed) { obj->spe += d(2,4); if (obj->spe > 20) obj->spe = 20; - p_glow2(obj,blue); + p_glow2(obj, NH_BLUE); } else { obj->spe += rnd(4); if (obj->spe > 20) obj->spe = 20; @@ -702,7 +691,7 @@ Your("%s %s covered by a %s %s %s!", xname(otmp), otense(otmp, "are"), sobj->cursed ? "mottled" : "shimmering", - hcolor(sobj->cursed ? Black : golden), + hcolor(sobj->cursed ? NH_BLACK : NH_GOLDEN), sobj->cursed ? "glow" : (is_shield(otmp) ? "layer" : "shield")); } @@ -715,6 +704,7 @@ } break; } + /* elven armor vibrates warningly when enchanted beyond a limit */ special_armor = is_elven_armor(otmp) || (Role_if(PM_WIZARD) && otmp->otyp == CORNUTHAUM); if (sobj->cursed) @@ -736,7 +726,7 @@ otense(otmp, Blind ? "vibrate" : "glow"), (!Blind && !same_color) ? " " : nul, (Blind || same_color) ? nul : - hcolor(sobj->cursed ? Black : silver), + hcolor(sobj->cursed ? NH_BLACK : NH_SILVER), otense(otmp, "evaporate")); if(is_cloak(otmp)) (void) Cloak_off(); if(is_boots(otmp)) (void) Boots_off(); @@ -772,7 +762,7 @@ s == 0 ? "violently " : nul, otense(otmp, Blind ? "vibrate" : "glow"), (!Blind && !same_color) ? " " : nul, - (Blind || same_color) ? nul : hcolor(sobj->cursed ? Black : silver), + (Blind || same_color) ? nul : hcolor(sobj->cursed ? NH_BLACK : NH_SILVER), (s*s>1) ? "while" : "moment"); otmp->cursed = sobj->cursed; if (!otmp->blessed || sobj->cursed) @@ -801,7 +791,7 @@ return(1); } otmp->oerodeproof = sobj->cursed; - p_glow2(otmp,purple); + p_glow2(otmp, NH_PURPLE); break; } if(!sobj->cursed || !otmp || !otmp->cursed) { @@ -829,11 +819,11 @@ Your("%s begin to %s%s.", makeplural(body_part(HAND)), Blind ? "tingle" : "glow ", - Blind ? nul : hcolor(purple)); + Blind ? nul : hcolor(NH_PURPLE)); make_confused(HConfusion + rnd(100),FALSE); } else { pline("A %s%s surrounds your %s.", - Blind ? nul : hcolor(red), + Blind ? nul : hcolor(NH_RED), Blind ? "faint buzz" : " glow", body_part(HEAD)); make_confused(0L,TRUE); @@ -843,7 +833,7 @@ Your("%s%s %s%s.", makeplural(body_part(HAND)), Blind ? "" : " begin to glow", - Blind ? (const char *)"tingle" : hcolor(red), + Blind ? (const char *)"tingle" : hcolor(NH_RED), u.umconf ? " even more" : ""); u.umconf++; } else { @@ -855,7 +845,7 @@ Your("%s glow a%s brilliant %s.", makeplural(body_part(HAND)), u.umconf ? "n even more" : "", - hcolor(red)); + hcolor(NH_RED)); /* after a while, repeated uses become less effective */ if (u.umconf >= 40) u.umconf++; @@ -915,15 +905,43 @@ if (sobj->cursed) { pline_The("scroll disintegrates."); } else { - for (obj = invent; obj; obj = obj->nobj) - if (sobj->blessed || - (obj->owornmask && - ((obj->owornmask & ~W_SWAPWEP) || u.twoweap)) || + for (obj = invent; obj; obj = obj->nobj) { + long wornmask; +#ifdef GOLDOBJ + /* gold isn't subject to cursing and blessing */ + if (obj->oclass == COIN_CLASS) continue; +#endif + wornmask = (obj->owornmask & ~(W_BALL|W_ART|W_ARTI)); + if (wornmask && !sobj->blessed) { + /* handle a couple of special cases; we don't + allow auxiliary weapon slots to be used to + artificially increase number of worn items */ + if (obj == uswapwep) { + if (!u.twoweap) wornmask = 0L; + } else if (obj == uquiver) { + if (obj->oclass == WEAPON_CLASS) { + /* mergeable weapon test covers ammo, + missiles, spears, daggers & knives */ + if (!objects[obj->otyp].oc_merge) + wornmask = 0L; + } else if (obj->oclass == GEM_CLASS) { + /* possibly ought to check whether + alternate weapon is a sling... */ + if (!uslinging()) wornmask = 0L; + } else { + /* weptools don't merge and aren't + reasonable quivered weapons */ + wornmask = 0L; + } + } + } + if (sobj->blessed || wornmask || obj->otyp == LOADSTONE || (obj->otyp == LEASH && obj->leashmon)) { if(confused) blessorcurse(obj, 2); else uncurse(obj); } + } } if(Punished && !confused) unpunish(); update_inventory(); @@ -952,7 +970,7 @@ Your("%s covered by a %s %s %s!", aobjnam(uwep, "are"), sobj->cursed ? "mottled" : "shimmering", - hcolor(sobj->cursed ? purple : golden), + hcolor(sobj->cursed ? NH_PURPLE : NH_GOLDEN), sobj->cursed ? "glow" : "shield"); } if (uwep->oerodeproof && (uwep->oeroded || uwep->oeroded2)) { @@ -1409,7 +1427,7 @@ static void do_class_genocide() { - register int i, j, immunecnt, gonecnt, goodcnt, class; + int i, j, immunecnt, gonecnt, goodcnt, class, feel_dead = 0; char buf[BUFSZ]; boolean gameover = FALSE; /* true iff killed self */ @@ -1424,7 +1442,8 @@ (void)mungspaces(buf); } while (buf[0]=='\033' || !buf[0]); /* choosing "none" preserves genocideless conduct */ - if (!strcmpi(buf, "none")) return; + if (!strcmpi(buf, "none") || + !strcmpi(buf, "nothing")) return; if (strlen(buf) == 1) { if (buf[0] == ILLOBJ_SYM) @@ -1499,19 +1518,26 @@ update_inventory(); /* eggs & tins */ pline("Wiped out all %s.", nam); if (Upolyd && i == u.umonnum) { - if (Unchanging) done(GENOCIDED); - rehumanize(); + u.mh = -1; + if (Unchanging) { + if (!feel_dead++) You("die."); + /* finish genociding this class of + monsters before ultimately dying */ + gameover = TRUE; + } else + rehumanize(); } - /* Self-genocide if it matches either your race or role */ - /* Assumption: male and female forms share the same letter */ + /* Self-genocide if it matches either your race + or role. Assumption: male and female forms + share same monster class. */ if (i == urole.malenum || i == urace.malenum) { u.uhp = -1; - killer_format = KILLED_BY_AN; - killer = "scroll of genocide"; - if (Upolyd) - You_feel("dead inside."); - else + if (Upolyd) { + if (!feel_dead++) You_feel("dead inside."); + } else { + if (!feel_dead++) You("die."); gameover = TRUE; + } } } else if (mvitals[i].mvflags & G_GENOD) { if (!gameover) @@ -1542,7 +1568,11 @@ } } } - if (gameover) done(GENOCIDED); + if (gameover || u.uhp == -1) { + killer_format = KILLED_BY_AN; + killer = "scroll of genocide"; + if (gameover) done(GENOCIDED); + } return; } } @@ -1579,7 +1609,7 @@ buf); (void)mungspaces(buf); /* choosing "none" preserves genocideless conduct */ - if (!strcmpi(buf, "none")) { + if (!strcmpi(buf, "none") || !strcmpi(buf, "nothing")) { /* ... but no free pass if cursed */ if (!(how & REALLY)) { ptr = rndmonst(); @@ -1766,44 +1796,59 @@ } #ifdef WIZARD +/* + * Make a new monster with the type controlled by the user. + * + * Note: when creating a monster by class letter, specifying the + * "strange object" (']') symbol produces a random monster rather + * than a mimic; this behavior quirk is useful so don't "fix" it... + */ boolean create_particular() { - char buf[BUFSZ], monclass = MAXMCLASSES; - int which = PM_PLAYERMON, tries = 0, i; - struct permonst *whichpm = 0; + char buf[BUFSZ], *bufp, monclass = MAXMCLASSES; + int which, tries, i; + struct permonst *whichpm; struct monst *mtmp; boolean madeany = FALSE; - boolean maketame = FALSE; + boolean maketame, makepeaceful, makehostile; + tries = 0; do { + which = urole.malenum; /* an arbitrary index into mons[] */ + maketame = makepeaceful = makehostile = FALSE; getlin("Create what kind of monster? [type the name or symbol]", buf); - if (buf[0] == '\033') return FALSE; - (void)mungspaces(buf); - if (strlen(buf) == 1) { - monclass = def_char_to_monclass(buf[0]); - if (monclass == MAXMCLASSES) - pline("I've never heard of such monsters."); - else break; + bufp = mungspaces(buf); + if (*bufp == '\033') return FALSE; + /* allow the initial disposition to be specified */ + if (!strncmpi(bufp, "tame ", 5)) { + bufp += 5; + maketame = TRUE; + } else if (!strncmpi(bufp, "peaceful ", 9)) { + bufp += 9; + makepeaceful = TRUE; + } else if (!strncmpi(bufp, "hostile ", 8)) { + bufp += 8; + makehostile = TRUE; + } + /* decide whether a valid monster was chosen */ + if (strlen(bufp) == 1) { + monclass = def_char_to_monclass(*bufp); + if (monclass != MAXMCLASSES) break; /* got one */ } else { - if (!strncmpi(buf, "tame ", 5)) { - which = name_to_mon(buf+5); - maketame = TRUE; - } else { - which = name_to_mon(buf); - maketame = FALSE; - } - if (which < LOW_PM) pline("I've never heard of such monsters."); - else { - whichpm = &mons[which]; - break; - } + which = name_to_mon(bufp); + if (which >= LOW_PM) break; /* got one */ } + /* no good; try again... */ + pline("I've never heard of such monsters."); } while (++tries < 5); - if (tries == 5) pline(thats_enough_tries); - else { + + if (tries == 5) { + pline(thats_enough_tries); + } else { (void) cant_create(&which, FALSE); + whichpm = &mons[which]; for (i = 0; i <= multi; i++) { if (monclass != MAXMCLASSES) whichpm = mkclass(monclass, 0); @@ -1813,8 +1858,14 @@ initedog(mtmp); set_malign(mtmp); } - } else + } else { mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS); + if ((makepeaceful || makehostile) && mtmp) { + mtmp->mtame = 0; /* sanity precaution */ + mtmp->mpeaceful = makepeaceful ? 1 : 0; + set_malign(mtmp); + } + } if (mtmp) madeany = TRUE; } } diff -Naurd ../nethack-3.4.0/src/region.c ./src/region.c --- ../nethack-3.4.0/src/region.c Wed Mar 20 23:43:15 2002 +++ ./src/region.c Mon Feb 24 15:25:05 2003 @@ -43,6 +43,7 @@ NhRegion *FDECL(create_force_field, (XCHAR_P,XCHAR_P,int,int)); #endif +static void FDECL(reset_region_mids, (NhRegion *)); static callback_proc callbacks[] = { #define INSIDE_GAS_CLOUD 0 @@ -124,7 +125,8 @@ reg->leave_f = NO_CALLBACK; reg->can_leave_f = NO_CALLBACK; reg->inside_f = NO_CALLBACK; - reg->player_inside = FALSE; + clear_hero_inside(reg); + clear_heros_fault(reg); reg->n_monst = 0; reg->max_monst = 0; reg->monsters = NULL; @@ -245,7 +247,7 @@ ret_reg->can_enter_f = reg->can_enter_f; ret_reg->leave_f = reg->leave_f; ret_reg->can_leave_f = reg->can_leave_f; - ret_reg->player_inside = reg->player_inside; + ret_reg->player_flags = reg->player_flags; /* set/clear_hero_inside,&c*/ ret_reg->n_monst = reg->n_monst; if (reg->n_monst > 0) { ret_reg->monsters = (unsigned *) @@ -310,7 +312,10 @@ newsym(i, j); } /* Check for player now... */ - reg->player_inside = inside_region(reg, u.ux, u.uy); + if (inside_region(reg, u.ux, u.uy)) + set_hero_inside(reg); + else + clear_hero_inside(reg); } /* @@ -387,7 +392,7 @@ regions[i]->ttl--; /* Check if player is inside region */ f_indx = regions[i]->inside_f; - if (f_indx != NO_CALLBACK && regions[i]->player_inside) + if (f_indx != NO_CALLBACK && hero_inside(regions[i])) (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); /* Check if any monster is inside region */ if (f_indx != NO_CALLBACK) { @@ -420,12 +425,12 @@ /* First check if we can do the move */ for (i = 0; i < n_regions; i++) { if (inside_region(regions[i], x, y) - && !regions[i]->player_inside && !regions[i]->attach_2_u) { + && !hero_inside(regions[i]) && !regions[i]->attach_2_u) { if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK) if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0)) return FALSE; } else - if (regions[i]->player_inside + if (hero_inside(regions[i]) && !inside_region(regions[i], x, y) && !regions[i]->attach_2_u) { if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK) @@ -436,9 +441,9 @@ /* Callbacks for the regions we do leave */ for (i = 0; i < n_regions; i++) - if (regions[i]->player_inside && + if (hero_inside(regions[i]) && !regions[i]->attach_2_u && !inside_region(regions[i], x, y)) { - regions[i]->player_inside = FALSE; + clear_hero_inside(regions[i]); if (regions[i]->leave_msg != NULL) pline(regions[i]->leave_msg); if ((f_indx = regions[i]->leave_f) != NO_CALLBACK) @@ -447,9 +452,9 @@ /* Callbacks for the regions we do enter */ for (i = 0; i < n_regions; i++) - if (!regions[i]->player_inside && + if (!hero_inside(regions[i]) && !regions[i]->attach_2_u && inside_region(regions[i], x, y)) { - regions[i]->player_inside = TRUE; + set_hero_inside(regions[i]); if (regions[i]->enter_msg != NULL) pline(regions[i]->enter_msg); if ((f_indx = regions[i]->enter_f) != NO_CALLBACK) @@ -497,7 +502,7 @@ /* Callbacks for the regions we do enter */ for (i = 0; i < n_regions; i++) - if (!regions[i]->player_inside && + if (!hero_inside(regions[i]) && !regions[i]->attach_2_u && inside_region(regions[i], x, y)) { add_mon_to_reg(regions[i], mon); if ((f_indx = regions[i]->enter_f) != NO_CALLBACK) @@ -515,10 +520,10 @@ register int i; for (i = 0; i < n_regions; i++) - if (!regions[i]->attach_2_u) - regions[i]->player_inside = inside_region(regions[i], u.ux, u.uy); + if (!regions[i]->attach_2_u && inside_region(regions[i], u.ux, u.uy)) + set_hero_inside(regions[i]); else - regions[i]->player_inside = FALSE; + clear_hero_inside(regions[i]); } /* @@ -641,7 +646,7 @@ bwrite(fd, (genericptr_t) ®ions[i]->can_leave_f, sizeof (short)); bwrite(fd, (genericptr_t) ®ions[i]->leave_f, sizeof (short)); bwrite(fd, (genericptr_t) ®ions[i]->inside_f, sizeof (short)); - bwrite(fd, (genericptr_t) ®ions[i]->player_inside, sizeof (boolean)); + bwrite(fd, (genericptr_t) ®ions[i]->player_flags, sizeof (boolean)); bwrite(fd, (genericptr_t) ®ions[i]->n_monst, sizeof (short)); for (j = 0; j < regions[i]->n_monst; j++) bwrite(fd, (genericptr_t) ®ions[i]->monsters[j], @@ -657,8 +662,9 @@ } void -rest_regions(fd) +rest_regions(fd, ghostly) int fd; +boolean ghostly; /* If a bones file restore */ { int i, j; unsigned n; @@ -667,7 +673,8 @@ clear_regions(); /* Just for security */ mread(fd, (genericptr_t) &tmstamp, sizeof (tmstamp)); - tmstamp = (moves - tmstamp); + if (ghostly) tmstamp = 0; + else tmstamp = (moves - tmstamp); mread(fd, (genericptr_t) &n_regions, sizeof (n_regions)); max_regions = n_regions; if (n_regions > 0) @@ -714,7 +721,11 @@ mread(fd, (genericptr_t) ®ions[i]->can_leave_f, sizeof (short)); mread(fd, (genericptr_t) ®ions[i]->leave_f, sizeof (short)); mread(fd, (genericptr_t) ®ions[i]->inside_f, sizeof (short)); - mread(fd, (genericptr_t) ®ions[i]->player_inside, sizeof (boolean)); + mread(fd, (genericptr_t) ®ions[i]->player_flags, sizeof (boolean)); + if (ghostly) { /* settings pertained to old player */ + clear_hero_inside(regions[i]); + clear_heros_fault(regions[i]); + } mread(fd, (genericptr_t) ®ions[i]->n_monst, sizeof (short)); if (regions[i]->n_monst > 0) regions[i]->monsters = @@ -729,10 +740,33 @@ mread(fd, (genericptr_t) ®ions[i]->glyph, sizeof (int)); mread(fd, (genericptr_t) ®ions[i]->arg, sizeof (genericptr_t)); } - /* remove expired regions, do not trigger the expire_f callback (yet!) */ + /* remove expired regions, do not trigger the expire_f callback (yet!); + also update monster lists if this data is coming from a bones file */ for (i = n_regions - 1; i >= 0; i--) if (regions[i]->ttl == 0) remove_region(regions[i]); + else if (ghostly && regions[i]->n_monst > 0) + reset_region_mids(regions[i]); +} + +/* update monster IDs for region being loaded from bones; `ghostly' implied */ +static void +reset_region_mids(reg) +NhRegion *reg; +{ + int i = 0, n = reg->n_monst; + unsigned *mid_list = reg->monsters; + + while (i < n) + if (!lookup_id_mapping(mid_list[i], &mid_list[i])) { + /* shrink list to remove missing monster; order doesn't matter */ + mid_list[i] = mid_list[--n]; + } else { + /* move on to next monster */ + ++i; + } + reg->n_monst = n; + return; } #if 0 @@ -818,6 +852,8 @@ tmprect.hy--; } ff->ttl = ttl; + if (!in_mklev && !flags.mon_moving) + set_heros_fault(ff); /* assume player has created it */ /* ff->can_enter_f = enter_force_field; */ /* ff->can_leave_f = enter_force_field; */ add_region(ff); @@ -898,7 +934,10 @@ return FALSE; mtmp->mhp -= rnd(dam) + 5; if (mtmp->mhp <= 0) { - killed(mtmp); + if (heros_fault(reg)) + killed(mtmp); + else + monkilled(mtmp, "gas cloud", AD_DRST); if (mtmp->mhp <= 0) { /* not lifesaved */ return TRUE; } @@ -932,6 +971,8 @@ tmprect.hy--; } cloud->ttl = rn1(3,4); + if (!in_mklev && !flags.mon_moving) + set_heros_fault(cloud); /* assume player has created it */ cloud->inside_f = INSIDE_GAS_CLOUD; cloud->expire_f = EXPIRE_GAS_CLOUD; cloud->arg = (genericptr_t) damage; diff -Naurd ../nethack-3.4.0/src/restore.c ./src/restore.c --- ../nethack-3.4.0/src/restore.c Wed Mar 20 23:43:15 2002 +++ ./src/restore.c Mon Feb 24 15:25:05 2003 @@ -6,7 +6,7 @@ #include "lev.h" #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */ -#ifdef MICRO +#if defined(MICRO) extern int dotcnt; /* shared with save */ extern int dotrow; /* shared with save */ #endif @@ -106,6 +106,17 @@ for (otmp = invent; otmp; otmp = otmp2) { otmp2 = otmp->nobj; +#ifndef GOLDOBJ + if (otmp->oclass == COIN_CLASS) { + /* in_use gold is created by some menu operations */ + if (!otmp->in_use) { + impossible("inven_inuse: !in_use gold in inventory"); + } + extract_nobj(otmp, &invent); + otmp->in_use = FALSE; + dealloc_obj(otmp); + } else +#endif /* GOLDOBJ */ if (otmp->in_use) { if (!quietly) pline("Finishing off %s...", xname(otmp)); useup(otmp); @@ -344,6 +355,8 @@ register int fd; unsigned int *stuckid, *steedid; /* STEED */ { + /* discover is actually flags.explore */ + boolean remember_discover = discover; struct obj *otmp; int uid; @@ -360,6 +373,7 @@ mread(fd, (genericptr_t) &flags, sizeof(struct flag)); flags.bypasses = 0; /* never use the saved value of bypasses */ + if (remember_discover) discover = remember_discover; role_init(); /* Reset the initial role, race, gender, and alignment */ #ifdef AMII_GRAPHICS @@ -470,10 +484,14 @@ #endif { register int nfd; + char whynot[BUFSZ]; - nfd = create_levelfile(ltmp); - - if (nfd < 0) panic("Cannot open temp level %d!", ltmp); + nfd = create_levelfile(ltmp, whynot); + if (nfd < 0) { + /* BUG: should suppress any attempt to write a panic + save file if file creation is now failing... */ + panic("restlevelfile: %s", whynot); + } #ifdef MFLOPPY if (!savelev(nfd, ltmp, COUNT_SAVE)) { @@ -528,6 +546,10 @@ int rtmp; struct obj *otmp; +#ifdef STORE_PLNAME_IN_FILE + mread(fd, (genericptr_t) plname, PL_NSIZ); +#endif + restoring = TRUE; getlev(fd, 0, (xchar)0, FALSE); if (!restgamestate(fd, &stuckid, &steedid)) { @@ -607,6 +629,9 @@ (void) lseek(fd, (off_t)0, 0); #endif (void) uptodate(fd, (char *)0); /* skip version info */ +#ifdef STORE_PLNAME_IN_FILE + mread(fd, (genericptr_t) plname, PL_NSIZ); +#endif getlev(fd, 0, (xchar)0, FALSE); (void) close(fd); @@ -654,11 +679,13 @@ } void -trickery() +trickery(reason) +char *reason; { pline("Strange, this map is not as I remember it."); pline("Somebody is trying some trickery here..."); pline("This game is void."); + killer = reason; done(TRICKED); } @@ -698,16 +725,18 @@ #else mread(fd, (genericptr_t) &dlvl, sizeof(dlvl)); #endif - if((pid && pid != hpid) || (lev && dlvl != lev)) { + if ((pid && pid != hpid) || (lev && dlvl != lev)) { + char trickbuf[BUFSZ]; + + if (pid && pid != hpid) + Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!", + hpid, pid); + else + Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev); #ifdef WIZARD - if (wizard) { - if (pid && pid != hpid) - pline("PID (%d) doesn't match saved PID (%d)!", hpid, pid); - else if (lev && dlvl != lev) - pline("This is level %d, not %d!", dlvl, lev); - } + if (wizard) pline(trickbuf); #endif - trickery(); + trickery(trickbuf); } #ifdef RLECOMP @@ -810,7 +839,7 @@ } restdamage(fd, ghostly); - rest_regions(fd); + rest_regions(fd, ghostly); if (ghostly) { /* Now get rid of all the temp fruits... */ freefruitchn(oldfruit), oldfruit = 0; @@ -1005,6 +1034,7 @@ register unsigned len; { /*register int readlen = 0;*/ + if (fd < 0) error("Restore error; mread attempting to read file %d.", fd); mreadfd = fd; while (len--) { if (inrunlength > 0) { diff -Naurd ../nethack-3.4.0/src/rip.c ./src/rip.c --- ../nethack-3.4.0/src/rip.c Wed Mar 20 23:43:16 2002 +++ ./src/rip.c Mon Feb 24 15:25:05 2003 @@ -6,7 +6,7 @@ STATIC_DCL void FDECL(center, (int, char *)); -extern const char *killed_by_prefix[]; +extern const char * const killed_by_prefix[]; /* from topten.c */ #if defined(TTY_GRAPHICS) || defined(X11_GRAPHICS) || defined(GEM_GRAPHICS) || defined(MSWIN_GRAPHICS) # define TEXT_TOMBSTONE diff -Naurd ../nethack-3.4.0/src/role.c ./src/role.c --- ../nethack-3.4.0/src/role.c Wed Mar 20 23:43:16 2002 +++ ./src/role.c Mon Feb 24 15:25:05 2003 @@ -1100,7 +1100,7 @@ { int k, gendercount = 0, aligncount = 0; char buf[BUFSZ]; - char *err_ret = " character's"; + static char err_ret[] = " character's"; boolean donefirst = FALSE; if (!suppliedbuf || buflen < 1) return err_ret; diff -Naurd ../nethack-3.4.0/src/save.c ./src/save.c --- ../nethack-3.4.0/src/save.c Wed Mar 20 23:43:16 2002 +++ ./src/save.c Mon Feb 24 15:25:05 2003 @@ -1,9 +1,10 @@ -/* SCCS Id: @(#)save.c 3.4 2002/01/19 */ +/* SCCS Id: @(#)save.c 3.4 2002/08/22 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" +#include "quest.h" #ifndef NO_SIGNAL #include @@ -12,8 +13,6 @@ #include #endif -#include "quest.h" - #ifdef MFLOPPY long bytes_counted; static int count_only; @@ -66,6 +65,7 @@ program_state.done_hup = 0; #endif if(dosave0()) { + program_state.something_worth_saving = 0; u.uhp = -1; /* universal game's over indicator */ /* make sure they see the Saving message */ display_nhwindow(WIN_MESSAGE, TRUE); @@ -116,6 +116,7 @@ register int fd, ofd; xchar ltmp; d_level uz_save; + char whynot[BUFSZ]; if (!SAVEF[0]) return 0; @@ -149,7 +150,6 @@ HUP mark_synch(); /* flush any buffered screen output */ fd = create_savefile(); - if(fd < 0) { HUP pline("Cannot open save file."); (void) delete_savefile(); /* ab@unido */ @@ -203,6 +203,9 @@ #endif /* MFLOPPY */ store_version(fd); +#ifdef STORE_PLNAME_IN_FILE + bwrite(fd, (genericptr_t) plname, PL_NSIZ); +#endif ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); #ifdef STEED usteed_id = (u.usteed ? u.usteed->m_id : 0); @@ -239,11 +242,12 @@ } mark_synch(); #endif - ofd = open_levelfile(ltmp); + ofd = open_levelfile(ltmp, whynot); if (ofd < 0) { - HUP pline("Cannot read level %d.", ltmp); + HUP pline("%s", whynot); (void) close(fd); (void) delete_savefile(); + HUP killer = whynot; HUP done(TRICKED); return(0); } @@ -324,6 +328,7 @@ { int fd, hpid; static boolean havestate = TRUE; + char whynot[BUFSZ]; /* When checkpointing is on, the full state needs to be written * on each checkpoint. When checkpointing is off, only the pid @@ -343,24 +348,30 @@ * to any internal compression schemes since they must be * readable by an external utility */ - fd = open_levelfile(0); + fd = open_levelfile(0, whynot); if (fd < 0) { - pline("Cannot open level 0."); + pline("%s", whynot); pline("Probably someone removed it."); + killer = whynot; done(TRICKED); return; } (void) read(fd, (genericptr_t) &hpid, sizeof(hpid)); if (hackpid != hpid) { - pline("Level 0 pid bad!"); + Sprintf(whynot, + "Level #0 pid (%d) doesn't match ours (%d)!", + hpid, hackpid); + pline("%s", whynot); + killer = whynot; done(TRICKED); } (void) close(fd); - fd = create_levelfile(0); + fd = create_levelfile(0, whynot); if (fd < 0) { - pline("Cannot rewrite level 0."); + pline("%s", whynot); + killer = whynot; done(TRICKED); return; } @@ -371,6 +382,9 @@ (void) write(fd, (genericptr_t) &currlev, sizeof(currlev)); save_savefile_name(fd); store_version(fd); +#ifdef STORE_PLNAME_IN_FILE + bwrite(fd, (genericptr_t) plname, PL_NSIZ); +#endif ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); #ifdef STEED usteed_id = (u.usteed ? u.usteed->m_id : 0); @@ -1021,7 +1035,7 @@ } # ifdef WIZARD if (wizard) { - pline("Swapping in `%s'", from); + pline("Swapping in `%s'.", from); wait_synch(); } # endif diff -Naurd ../nethack-3.4.0/src/shk.c ./src/shk.c --- ../nethack-3.4.0/src/shk.c Wed Mar 20 23:43:17 2002 +++ ./src/shk.c Mon Feb 24 15:25:05 2003 @@ -24,6 +24,7 @@ #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE) extern const struct shclass shtypes[]; /* defined in shknam.c */ +extern struct obj *thrownobj; /* defined in dothrow.c */ STATIC_VAR NEARDATA long int followmsg; /* last time of follow message */ @@ -51,7 +52,7 @@ STATIC_DCL void FDECL(shk_names_obj, (struct monst *,struct obj *,const char *,long,const char *)); STATIC_DCL struct obj *FDECL(bp_to_obj, (struct bill_x *)); -STATIC_DCL boolean FDECL(inherits, (struct monst *, int, BOOLEAN_P)); +STATIC_DCL boolean FDECL(inherits, (struct monst *,int,int)); STATIC_DCL void FDECL(set_repo_loc, (struct eshk *)); STATIC_DCL boolean NDECL(angry_shk_exists); STATIC_DCL void FDECL(rile_shk, (struct monst *)); @@ -64,7 +65,7 @@ STATIC_DCL void FDECL(bill_box_content, (struct obj *, BOOLEAN_P, BOOLEAN_P, struct monst *)); #ifdef OVL1 -static void FDECL(rob_shop, (struct monst *)); +static boolean FDECL(rob_shop, (struct monst *)); #endif #ifdef OVLB @@ -88,7 +89,8 @@ Returns the amount actually paid, so we can know if the monster kept the change. */ -long money2mon(mon, amount) +long +money2mon(mon, amount) struct monst *mon; long amount; { @@ -103,8 +105,10 @@ return 0L; } - if (ygold->quan > amount) ygold = splitobj(ygold, amount); - else if (ygold->owornmask) remove_worn_item(ygold); /* quiver */ + if (ygold->quan > amount) + ygold = splitobj(ygold, amount); + else if (ygold->owornmask) + remove_worn_item(ygold, FALSE); /* quiver */ freeinv(ygold); add_to_minv(mon, ygold); flags.botl = 1; @@ -282,6 +286,7 @@ clear_unpaid(invent); clear_unpaid(fobj); clear_unpaid(level.buriedobjlist); + if (thrownobj) thrownobj->unpaid = 0; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) clear_unpaid(mtmp->minvent); for(mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) @@ -423,13 +428,13 @@ return; } - rob_shop(shkp); - + if (rob_shop(shkp)) { #ifdef KOPS - call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge)); + call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge)); #else - (void) angry_guards(FALSE); + (void) angry_guards(FALSE); #endif + } } /* robbery from outside the shop via telekinesis or grappling hook */ @@ -448,17 +453,19 @@ if (!eshkp->billct && !eshkp->debit) /* bill is settled */ return; - rob_shop(shkp); - + if (rob_shop(shkp)) { #ifdef KOPS - /* [might want to set 2nd arg based on distance from shop doorway] */ - call_kops(shkp, FALSE); + /*[might want to set 2nd arg based on distance from shop doorway]*/ + call_kops(shkp, FALSE); #else - (void) angry_guards(FALSE); + (void) angry_guards(FALSE); #endif + } } -static void +/* shop merchandize has been taken; pay for it with any credit available; + return false if the debt is fully covered by credit, true otherwise */ +static boolean rob_shop(shkp) struct monst *shkp; { @@ -476,7 +483,7 @@ total -= eshkp->credit; } setpaid(shkp); - if (!total) return; + if (!total) return FALSE; /* by this point, we know an actual robbery has taken place */ eshkp->robbed += total; @@ -486,6 +493,7 @@ adjalign(-sgn(u.ualign.type)); hot_pursuit(shkp); + return TRUE; } void @@ -610,7 +618,8 @@ making sure they're unpaid and the same type of object; we check the price quoted by the shopkeeper and also that they both belong to the same shk. */ -boolean same_price(obj1, obj2) +boolean +same_price(obj1, obj2) struct obj *obj1, *obj2; { register struct monst *shkp1, *shkp2; @@ -889,6 +898,7 @@ #endif pacify_guards(); } + after_shk_move(shkp); } STATIC_OVL boolean @@ -989,10 +999,11 @@ if(!shkp->isshk) return; rile_shk(shkp); + (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ); ESHK(shkp)->following = 1; } -/* used when the shkp is teleported out of his shop, +/* used when the shkp is teleported or falls (ox == 0) out of his shop, * or when the player is not on a costly_spot and he * damages something inside the shop. these conditions * must be checked by the calling function. @@ -1019,7 +1030,7 @@ which makes this message look pretty silly, so temporarily restore her original location during the call to Monnam. */ sx = shkp->mx, sy = shkp->my; - if (cansee(ox, oy) && !cansee(sx, sy)) + if (isok(ox, oy) && cansee(ox, oy) && !cansee(sx, sy)) shkp->mx = ox, shkp->my = oy; pline("%s %s!", Monnam(shkp), !ANGRY(shkp) ? "gets angry" : "is furious"); @@ -1528,7 +1539,9 @@ } pay(ltmp, shkp); - shk_names_obj(shkp, obj, "bought %s for %ld gold piece%s.%s", ltmp, ""); + shk_names_obj(shkp, obj, consumed ? + "paid for %s at a cost of %ld gold piece%s.%s" : + "bought %s for %ld gold piece%s.%s", ltmp, ""); obj->quan = save_quan; /* restore original count */ /* quan => amount just bought, save_quan => remaining unpaid count */ if (consumed) { @@ -1556,12 +1569,17 @@ /* routine called after dying (or quitting) */ boolean paybill(croaked) -boolean croaked; +int croaked; /* -1: escaped dungeon; 0: quit; 1: died */ { register struct monst *mtmp, *mtmp2, *resident= (struct monst *)0; register boolean taken = FALSE; register int numsk = 0; + /* if we escaped from the dungeon, shopkeepers can't reach us; + shops don't occur on level 1, but this could happen if hero + level teleports out of the dungeon and manages not to die */ + if (croaked < 0) return FALSE; + /* this is where inventory will end up if any shk takes it */ repo_location.x = repo_location.y = 0; @@ -1592,7 +1610,7 @@ inherits(shkp, numsk, croaked) struct monst *shkp; int numsk; -boolean croaked; +int croaked; { long loss = 0L; #ifdef GOLDOBJ @@ -1660,7 +1678,7 @@ if (loss > umoney || !loss || roomno == eshkp->shoproom) { eshkp->robbed -= umoney; if (eshkp->robbed < 0L) eshkp->robbed = 0L; - money2mon(shkp, umoney); + if (umoney > 0) money2mon(shkp, umoney); #endif flags.botl = 1; pline("%s %s all your possessions.", @@ -1726,7 +1744,8 @@ } /* called at game exit, after inventory disclosure but before making bones */ -void finish_paybill() +void +finish_paybill() { register struct obj *otmp; int ox = repo_location.x, @@ -1890,7 +1909,7 @@ /* the price of contained objects */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { - if (otmp->oclass == GOLD_CLASS) continue; + if (otmp->oclass == COIN_CLASS) continue; /* the "top" container is evaluated by caller */ if (usell) { if (saleable(shkp, otmp) && @@ -1920,7 +1939,7 @@ /* accumulate contained gold */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) - if (otmp->oclass == GOLD_CLASS) + if (otmp->oclass == COIN_CLASS) value += otmp->quan; else if (Has_contents(otmp)) value += contained_gold(otmp); @@ -1938,7 +1957,7 @@ /* the "top" container is treated in the calling fn */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { - if (otmp->oclass == GOLD_CLASS) continue; + if (otmp->oclass == COIN_CLASS) continue; if (!otmp->unpaid && !(sale && saleable(shkp, otmp))) otmp->no_charge = 1; @@ -1956,7 +1975,7 @@ /* the "top" container is treated in the calling fn */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { - if (otmp->oclass == GOLD_CLASS) continue; + if (otmp->oclass == COIN_CLASS) continue; if (otmp->no_charge) otmp->no_charge = 0; @@ -2091,7 +2110,7 @@ register struct obj *otmp; for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { - if (otmp->oclass == GOLD_CLASS) continue; + if (otmp->oclass == COIN_CLASS) continue; /* the "top" box is added in addtobill() */ if (!otmp->no_charge) @@ -2164,7 +2183,7 @@ return; } - if(obj->oclass == GOLD_CLASS) { + if(obj->oclass == COIN_CLASS) { costly_gold(obj->ox, obj->oy, obj->quan); return; } @@ -2338,7 +2357,7 @@ if (Has_contents(obj)) for(otmp = obj->cobj; otmp; otmp = otmp->nobj) { - if(otmp->oclass == GOLD_CLASS) continue; + if(otmp->oclass == COIN_CLASS) continue; if (Has_contents(otmp)) subfrombill(otmp, shkp); @@ -2370,7 +2389,7 @@ /* the price of contained objects, if any */ for(otmp = obj->cobj; otmp; otmp = otmp->nobj) { - if(otmp->oclass == GOLD_CLASS) continue; + if(otmp->oclass == COIN_CLASS) continue; if (!Has_contents(otmp)) { if(ininv) { @@ -2404,7 +2423,7 @@ if (!shkp || !inhishop(shkp)) return (0L); - if(obj->oclass == GOLD_CLASS) { + if(obj->oclass == COIN_CLASS) { gvalue += obj->quan; } else if (Has_contents(obj)) { register boolean ininv = !!count_unpaid(obj->cobj); @@ -2425,7 +2444,8 @@ ESHK(shkp)->debit += value; if(!silent) { - char *still = ""; + const char *still = ""; + if (credit_use) { if (ESHK(shkp)->credit) { You("have %ld %s credit remaining.", @@ -2437,11 +2457,12 @@ } still = "still "; } - if(obj->oclass == GOLD_CLASS) - You("%sowe %s %ld %s!", still, mon_nam(shkp), value, currency(value)); - else You("%sowe %s %ld %s for %s!", still, - mon_nam(shkp), - value, currency(value), + if(obj->oclass == COIN_CLASS) + You("%sowe %s %ld %s!", still, + mon_nam(shkp), value, currency(value)); + else + You("%sowe %s %ld %s for %s!", still, + mon_nam(shkp), value, currency(value), obj->quan > 1L ? "them" : "it"); } } else { @@ -2449,8 +2470,6 @@ if(!silent) { if(cansee(shkp->mx, shkp->my)) { - if(ESHK(shkp)->customer[0] == 0) - (void) strncpy(ESHK(shkp)->customer,plname,PL_NSIZ); Norep("%s booms: \"%s, you are a thief!\"", Monnam(shkp), plname); } else Norep("You hear a scream, \"Thief!\""); @@ -2492,7 +2511,7 @@ register struct eshk *eshkp; long ltmp = 0L, cltmp = 0L, gltmp = 0L, offer; boolean saleitem, cgold = FALSE, container = Has_contents(obj); - boolean isgold = (obj->oclass == GOLD_CLASS); + boolean isgold = (obj->oclass == COIN_CLASS); boolean only_partially_your_contents = FALSE; if(!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || @@ -2616,7 +2635,7 @@ || (obj->oclass == FOOD_CLASS && obj->oeaten) || (Is_candle(obj) && obj->age < 20L * (long)objects[obj->otyp].oc_cost)) { - pline("%s seems not interested%s.", Monnam(shkp), + pline("%s seems uninterested%s.", Monnam(shkp), cgold ? " in the rest" : ""); if (container) dropped_container(obj, shkp, FALSE); @@ -3255,8 +3274,24 @@ } } - return(move_special(shkp,inhishop(shkp), - appr,uondoor,avoid,omx,omy,gx,gy)); + z = move_special(shkp,inhishop(shkp),appr,uondoor,avoid,omx,omy,gx,gy); + if (z > 0) after_shk_move(shkp); + + return z; +} + +/* called after shopkeeper moves, in case the move causes re-entry into shop */ +void +after_shk_move(shkp) +struct monst *shkp; +{ + struct eshk *eshkp = ESHK(shkp); + + if (eshkp->bill_p == (struct bill_x *) -1000 && inhishop(shkp)) { + /* reset bill_p, need to re-calc player's occupancy too */ + eshkp->bill_p = &eshkp->bill[0]; + check_special_room(FALSE); + } } #endif /*OVL3*/ @@ -3276,14 +3311,17 @@ register int fall; { register struct monst *shkp = shop_keeper(*u.ushops); - int lang = 0; - char *grabs = "grabs"; + int lang; + const char *grabs = "grabs"; if(!shkp) return; /* 0 == can't speak, 1 == makes animal noises, 2 == speaks */ - if (!is_silent(shkp->data) && shkp->data->msound <= MS_ANIMAL) - lang = 1; + lang = 0; + if (shkp->msleeping || !shkp->mcanmove || is_silent(shkp->data)) + ; /* lang stays 0 */ + else if (shkp->data->msound <= MS_ANIMAL) + lang = 1; else if (shkp->data->msound >= MS_HUMANOID) lang = 2; @@ -3347,6 +3385,8 @@ if ((obj->owornmask & ~(W_SWAPWEP|W_QUIVER)) != 0 || (obj == uswapwep && u.twoweap) || (obj->otyp == LEASH && obj->leashmon)) continue; + if (obj == current_wand) continue; + setnotworn(obj); freeinv(obj); subfrombill(obj, shkp); (void) add_to_minv(shkp, obj); /* may free obj */ @@ -3382,8 +3422,9 @@ #endif /* KOPS */ void -pay_for_damage(dmgstr) +pay_for_damage(dmgstr, cant_mollify) const char *dmgstr; +boolean cant_mollify; { register struct monst *shkp = (struct monst *)0; char shops_affected[5]; @@ -3493,11 +3534,11 @@ (void) mnearto(shkp, x, y, TRUE); } - if((um_dist(x, y, 1) && !uinshp) || + if((um_dist(x, y, 1) && !uinshp) || cant_mollify || #ifndef GOLDOBJ - (u.ugold + ESHK(shkp)->credit) < cost_of_damage + (u.ugold + ESHK(shkp)->credit) < cost_of_damage #else - (money_cnt(invent) + ESHK(shkp)->credit) < cost_of_damage + (money_cnt(invent) + ESHK(shkp)->credit) < cost_of_damage #endif || !rn2(50)) { if(um_dist(x, y, 1) && !uinshp) { @@ -3569,7 +3610,7 @@ return(struct obj *)0; for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) - if (otmp->oclass != GOLD_CLASS) + if (otmp->oclass != COIN_CLASS) break; /* note: otmp might have ->no_charge set, but that's ok */ return (otmp && costly_spot(x, y) && NOTANGRY(shkp) @@ -3593,7 +3634,7 @@ putstr(tmpwin, 0, "Fine goods for sale:"); putstr(tmpwin, 0, ""); for (otmp = first_obj; otmp; otmp = otmp->nexthere) { - if (otmp->oclass == GOLD_CLASS) continue; + if (otmp->oclass == COIN_CLASS) continue; cost = (otmp->no_charge || otmp == uball || otmp == uchain) ? 0L : get_cost(otmp, (struct monst *)0); if (Has_contents(otmp)) diff -Naurd ../nethack-3.4.0/src/shknam.c ./src/shknam.c --- ../nethack-3.4.0/src/shknam.c Wed Mar 20 23:43:17 2002 +++ ./src/shknam.c Mon Feb 24 15:25:05 2003 @@ -13,10 +13,10 @@ #else STATIC_DCL void FDECL(mkshobj_at, (const struct shclass *,int,int)); -STATIC_DCL void FDECL(nameshk, (struct monst *,const char **)); +STATIC_DCL void FDECL(nameshk, (struct monst *,const char * const *)); STATIC_DCL int FDECL(shkinit, (const struct shclass *,struct mkroom *)); -static const char *shkliquors[] = { +static const char * const shkliquors[] = { /* Ukraine */ "Njezjin", "Tsjernigof", "Gomel", "Ossipewsk", "Gorlowka", /* N. Russia */ @@ -31,7 +31,7 @@ 0 }; -static const char *shkbooks[] = { +static const char * const shkbooks[] = { /* Eire */ "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch", "Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra", @@ -42,7 +42,7 @@ 0 }; -static const char *shkarmors[] = { +static const char * const shkarmors[] = { /* Turquie */ "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep", "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak", @@ -53,11 +53,11 @@ 0 }; -static const char *shkwands[] = { +static const char * const shkwands[] = { /* Wales */ "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach", "Rhaeader", "Llandrindod", "Llanfair-ym-muallt", - "Y-Fenni", "Measteg", "Rhydaman", "Beddgelert", + "Y-Fenni", "Maesteg", "Rhydaman", "Beddgelert", "Curig", "Llanrwst", "Llanerchymedd", "Caergybi", /* Scotland */ "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar", @@ -67,7 +67,7 @@ 0 }; -static const char *shkrings[] = { +static const char * const shkrings[] = { /* Hollandse familienamen */ "Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken", "Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy", @@ -80,7 +80,7 @@ 0 }; -static const char *shkfoods[] = { +static const char * const shkfoods[] = { /* Indonesia */ "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan", "Bandjar", "Parbalingga", "Bojolali", "Sarangan", @@ -92,7 +92,7 @@ 0 }; -static const char *shkweapons[] = { +static const char * const shkweapons[] = { /* Perigord */ "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard", "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac", @@ -103,7 +103,7 @@ 0 }; -static const char *shktools[] = { +static const char * const shktools[] = { /* Spmi */ "Ymla", "Eed-morra", "Cubask", "Nieb", "Bnowr Falr", "Telloc Cyaj", "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil", @@ -134,7 +134,7 @@ 0 }; -static const char *shklight[] = { +static const char * const shklight[] = { /* Romania */ "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu", "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt", @@ -146,7 +146,7 @@ 0 }; -static const char *shkgeneral[] = { +static const char * const shkgeneral[] = { /* Suriname */ "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi", "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo", @@ -271,7 +271,7 @@ STATIC_OVL void nameshk(shk, nlp) struct monst *shk; -const char *nlp[]; +const char * const *nlp; { int i, trycnt, names_avail; const char *shname = 0; diff -Naurd ../nethack-3.4.0/src/sit.c ./src/sit.c --- ../nethack-3.4.0/src/sit.c Wed Mar 20 23:43:17 2002 +++ ./src/sit.c Mon Feb 24 15:25:05 2003 @@ -17,10 +17,11 @@ flags.botl = 1; } #else - struct obj *otmp; + struct obj *otmp, *nobj; int lost_money = 0; - for (otmp = invent; otmp; otmp = otmp->nobj) { - if (otmp->oclass == GOLD_CLASS) { + for (otmp = invent; otmp; otmp = nobj) { + nobj = otmp->nobj; + if (otmp->oclass == COIN_CLASS) { lost_money = 1; delobj(otmp); } @@ -37,7 +38,7 @@ int dosit() { - static const char *sit_message = "sit on the %s."; + static const char sit_message[] = "sit on the %s."; register struct trap *trap; register int typ = levl[u.ux][u.uy].typ; @@ -270,8 +271,8 @@ if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) { /* may have teleported */ - pline_The("throne vanishes in a puff of logic."); levl[u.ux][u.uy].typ = ROOM; + pline_The("throne vanishes in a puff of logic."); newsym(u.ux,u.uy); } @@ -312,7 +313,7 @@ int nobj = 0; int cnt, onum; struct obj *otmp; - static const char *mal_aura = "feel a malignant aura surround %s."; + static const char mal_aura[] = "feel a malignant aura surround %s."; if (uwep && (uwep->oartifact == ART_MAGICBANE) && rn2(20)) { You(mal_aura, "the magic-absorbing blade"); @@ -324,14 +325,27 @@ You(mal_aura, "you"); } - for (otmp = invent; otmp; otmp = otmp->nobj) nobj++; - + for (otmp = invent; otmp; otmp = otmp->nobj) { +#ifdef GOLDOBJ + /* gold isn't subject to being cursed or blessed */ + if (otmp->oclass == COIN_CLASS) continue; +#endif + nobj++; + } if (nobj) { for (cnt = rnd(6/((!!Antimagic) + (!!Half_spell_damage) + 1)); cnt > 0; cnt--) { - onum = rn2(nobj); - for(otmp = invent; onum != 0; onum--) - otmp = otmp->nobj; + onum = rnd(nobj); + for (otmp = invent; otmp; otmp = otmp->nobj) { +#ifdef GOLDOBJ + /* as above */ + if (otmp->oclass == COIN_CLASS) continue; +#endif + if (--onum == 0) break; /* found the target */ + } + /* the !otmp case should never happen; picking an already + cursed item happens--avoid "resists" message in that case */ + if (!otmp || otmp->cursed) continue; /* next target */ if(otmp->oartifact && spec_ability(otmp, SPFX_INTEL) && rn2(10) < 8) { @@ -346,6 +360,25 @@ } update_inventory(); } + +#ifdef STEED + /* treat steed's saddle as extended part of hero's inventory */ + if (u.usteed && !rn2(4) && + (otmp = which_armor(u.usteed, W_SADDLE)) != 0 && + !otmp->cursed) { /* skip if already cursed */ + if (otmp->blessed) + unbless(otmp); + else + curse(otmp); + if (!Blind) { + pline("%s %s %s.", + s_suffix(upstart(y_monnam(u.usteed))), + aobjnam(otmp, "glow"), + hcolor(otmp->cursed ? NH_BLACK : (const char *)"brown")); + otmp->bknown = TRUE; + } + } +#endif /*STEED*/ } void diff -Naurd ../nethack-3.4.0/src/sounds.c ./src/sounds.c --- ../nethack-3.4.0/src/sounds.c Wed Mar 20 23:43:17 2002 +++ ./src/sounds.c Mon Feb 24 15:25:05 2003 @@ -1,11 +1,13 @@ -/* SCCS Id: @(#)sounds.c 3.4 2001/02/14 */ +/* SCCS Id: @(#)sounds.c 3.4 2002/05/06 */ /* Copyright (c) 1989 Janet Walz, Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "edog.h" #ifdef USER_SOUNDS +# ifdef USER_SOUNDS_REGEX #include +# endif #endif #ifdef OVLB @@ -45,7 +47,7 @@ hallu = Hallucination ? 1 : 0; if (level.flags.nfountains && !rn2(400)) { - static const char *fountain_msg[4] = { + static const char * const fountain_msg[4] = { "bubbling water.", "water falling on coins.", "the splashing of a naiad.", @@ -55,7 +57,7 @@ } #ifdef SINK if (level.flags.nsinks && !rn2(300)) { - static const char *sink_msg[3] = { + static const char * const sink_msg[3] = { "a slow drip.", "a gurgling noise.", "dishes being washed!", @@ -64,7 +66,7 @@ } #endif if (level.flags.has_court && !rn2(200)) { - static const char *throne_msg[4] = { + static const char * const throne_msg[4] = { "the tones of courtly conversation.", "a sceptre pounded in judgment.", "Someone shouts \"Off with %s head!\"", @@ -86,7 +88,7 @@ } } if (level.flags.has_swamp && !rn2(200)) { - static const char *swamp_msg[3] = { + static const char * const swamp_msg[3] = { "hear mosquitoes!", "smell marsh gas!", /* so it's a smell...*/ "hear Donald Duck!", @@ -181,7 +183,7 @@ } } if (level.flags.has_barracks && !rn2(200)) { - static const char *barracks_msg[4] = { + static const char * const barracks_msg[4] = { "blades being honed.", "loud snoring.", "dice being thrown.", @@ -205,7 +207,7 @@ } } if (level.flags.has_zoo && !rn2(200)) { - static const char *zoo_msg[3] = { + static const char * const zoo_msg[3] = { "a sound reminiscent of an elephant stepping on a peanut.", "a sound reminiscent of a seal barking.", "Doctor Doolittle!", @@ -227,7 +229,7 @@ } if (tended_shop(sroom) && !index(u.ushops, ROOM_INDEX(sroom) + ROOMOFFSET)) { - static const char *shop_msg[3] = { + static const char * const shop_msg[3] = { "someone cursing shoplifters.", "the chime of a cash register.", "Neiman and Marcus arguing!", @@ -243,7 +245,7 @@ break; /* and don't produce silly effects when she's clearly visible */ if (mtmp && (hallu || !canseemon(mtmp))) { - static const char *ora_msg[5] = { + static const char * const ora_msg[5] = { "a strange wind.", /* Jupiter at Dodona */ "convulsive ravings.", /* Apollo at Delphi */ "snoring snakes.", /* AEsculapius at Epidaurus */ @@ -259,7 +261,7 @@ #endif /* OVL0 */ #ifdef OVLB -static const char *h_sounds[] = { +static const char * const h_sounds[] = { "beep", "boing", "sing", "belche", "creak", "cough", "rattle", "ululate", "pop", "jingle", "sniffle", "tinkle", "eep" }; @@ -495,7 +497,7 @@ verbl_msg = "I only drink... potions."; } else { int vampindex; - static const char *vampmsg[] = { + static const char * const vampmsg[] = { /* These first two (0 and 1) are specially handled below */ "I vant to suck your %s!", "I vill come after %s without regret!", @@ -623,7 +625,7 @@ break; case MS_LAUGH: { - static const char *laugh_msg[4] = { + static const char * const laugh_msg[4] = { "giggles.", "chuckles.", "snickers.", "laughs.", }; pline_msg = laugh_msg[rn2(4)]; @@ -739,7 +741,7 @@ verbalize("Just the facts, %s.", flags.female ? "Ma'am" : "Sir"); else { - static const char *arrest_msg[3] = { + static const char * const arrest_msg[3] = { "Anything you say can be used against you.", "You're under arrest!", "Stop in the name of the Law!", @@ -787,11 +789,11 @@ break; case MS_SOLDIER: { - static const char *soldier_foe_msg[3] = { + static const char * const soldier_foe_msg[3] = { "Resistance is useless!", "You're dog meat!", "Surrender!", - }, *soldier_pax_msg[3] = { + }, * const soldier_pax_msg[3] = { "What lousy pay we're getting here!", "The food's not fit for Orcs!", "My feet hurt, I've been on them all day!", @@ -860,7 +862,10 @@ return(1); } - (void) getdir("Talk to whom? (in what direction)"); + if (!getdir("Talk to whom? (in what direction)")) { + /* decided not to chat */ + return(0); + } #ifdef STEED if (u.usteed && u.dz > 0) @@ -902,6 +907,9 @@ return(0); } + /* if this monster is waiting for something, prod it into action */ + mtmp->mstrategy &= ~STRAT_WAITMASK; + if (mtmp->mtame && mtmp->meating) { if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); @@ -917,7 +925,11 @@ extern void FDECL(play_usersound, (const char*, int)); typedef struct audio_mapping_rec { +#ifdef USER_SOUNDS_REGEX struct re_pattern_buffer regex; +#else + char *pattern; +#endif char *filename; int volume; struct audio_mapping_rec *next; @@ -950,17 +962,25 @@ if (can_read_file(filespec)) { new_map = (audio_mapping *)alloc(sizeof(audio_mapping)); +#ifdef USER_SOUNDS_REGEX new_map->regex.translate = 0; new_map->regex.fastmap = 0; new_map->regex.buffer = 0; new_map->regex.allocated = 0; new_map->regex.regs_allocated = REGS_FIXED; +#else + new_map->pattern = (char *)alloc(strlen(text) + 1); + Strcpy(new_map->pattern, text); +#endif new_map->filename = strdup(filespec); new_map->volume = volume; new_map->next = soundmap; +#ifdef USER_SOUNDS_REGEX err = re_compile_pattern(text, strlen(text), &new_map->regex); - +#else + err = 0; +#endif if (err) { raw_print(err); free(new_map->filename); @@ -989,7 +1009,11 @@ audio_mapping* cursor = soundmap; while (cursor) { +#ifdef USER_SOUNDS_REGEX if (re_search(&cursor->regex, msg, strlen(msg), 0, 9999, 0) >= 0) { +#else + if (pmatch(cursor->pattern, msg)) { +#endif play_usersound(cursor->filename, cursor->volume); } cursor = cursor->next; diff -Naurd ../nethack-3.4.0/src/sp_lev.c ./src/sp_lev.c --- ../nethack-3.4.0/src/sp_lev.c Wed Mar 20 23:43:18 2002 +++ ./src/sp_lev.c Mon Feb 24 15:25:05 2003 @@ -945,7 +945,7 @@ panic("create_object: unexpected object class '%c'",c); /* KMH -- Create piles of gold properly */ - if (oclass == GOLD_CLASS) + if (oclass == COIN_CLASS) otmp = mkgold(0L, x, y); else otmp = mkobj_at(oclass, x, y, !named); @@ -1953,13 +1953,13 @@ } else r->monsters = 0; - /* read the objects */ + /* read the objects, in same order as mazes */ Fread((genericptr_t) &r->nobject, 1, sizeof(r->nobject), fd); if ((n = r->nobject) != 0) { r->objects = NewTab(object, n); - while (n--) { - r->objects[(int)n] = New(object); - load_one_object(fd, r->objects[(int)n]); + for (j = 0; j < n; ++j) { + r->objects[j] = New(object); + load_one_object(fd, r->objects[j]); } } else r->objects = 0; diff -Naurd ../nethack-3.4.0/src/spell.c ./src/spell.c --- ../nethack-3.4.0/src/spell.c Wed Mar 20 23:43:18 2002 +++ ./src/spell.c Mon Feb 24 15:25:05 2003 @@ -21,7 +21,8 @@ ((char)((spell < 26) ? ('a' + spell) : ('A' + spell - 26))) STATIC_DCL int FDECL(spell_let_to_idx, (CHAR_P)); -STATIC_DCL void FDECL(cursed_book, (int)); +STATIC_DCL boolean FDECL(cursed_book, (struct obj *bp)); +STATIC_DCL boolean FDECL(confused_book, (struct obj *)); STATIC_DCL void FDECL(deadbook, (struct obj *)); STATIC_PTR int NDECL(learn); STATIC_DCL boolean FDECL(getspell, (int *)); @@ -29,6 +30,7 @@ STATIC_DCL int FDECL(percent_success, (int)); STATIC_DCL int NDECL(throwspell); STATIC_DCL void NDECL(cast_protection); +STATIC_DCL void FDECL(spell_backfire, (int)); STATIC_DCL const char *FDECL(spelltypemnemonic, (int)); STATIC_DCL int FDECL(isqrt, (int)); @@ -102,10 +104,13 @@ return -1; } -STATIC_OVL void -cursed_book(lev) - register int lev; +/* TRUE: book should be destroyed by caller */ +STATIC_OVL boolean +cursed_book(bp) + struct obj *bp; { + int lev = objects[bp->otyp].oc_level; + switch(rn2(lev)) { case 0: You_feel("a wrenching sensation."); @@ -145,9 +150,12 @@ Blind ? "feel" : "look"); break; } + /* temp disable in_use; death should not destroy the book */ + bp->in_use = FALSE; losestr(Poison_resistance ? rn1(2,1) : rn1(4,3)); losehp(rnd(Poison_resistance ? 6 : 10), "contact-poisoned spellbook", KILLED_BY_AN); + bp->in_use = TRUE; break; case 6: if(Antimagic) { @@ -156,14 +164,39 @@ } else { pline("As you read the book, it %s in your %s!", explodes, body_part(FACE)); - losehp (2*rnd(10)+5, "exploding rune", KILLED_BY_AN); + losehp(2*rnd(10)+5, "exploding rune", KILLED_BY_AN); } - break; + return TRUE; default: rndcurse(); break; } - return; + return FALSE; +} + +/* study while confused: returns TRUE if the book is destroyed */ +STATIC_OVL boolean +confused_book(spellbook) +struct obj *spellbook; +{ + boolean gone = FALSE; + + if (!rn2(3) && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { + spellbook->in_use = TRUE; /* in case called from learn */ + pline( + "Being confused you have difficulties in controlling your actions."); + display_nhwindow(WIN_MESSAGE, FALSE); + You("accidentally tear the spellbook to pieces."); + if (!objects[spellbook->otyp].oc_name_known && + !objects[spellbook->otyp].oc_uname) + docall(spellbook); + useup(spellbook); + gone = TRUE; + } else { + You("find yourself reading the %s line over and over again.", + spellbook == book ? "next" : "first"); + } + return gone; } /* special effects for The Book of the Dead */ @@ -212,8 +245,15 @@ pline_The("invocation fails!"); pline("At least one of your artifacts is cursed..."); } else if(arti1_primed && arti2_primed) { + unsigned soon = (unsigned) d(2,6); /* time til next intervene() */ + + /* successful invocation */ mkinvokearea(); u.uevent.invoked = 1; + /* in case you haven't killed the Wizard yet, behave as if + you just did */ + u.uevent.udemigod = 1; /* wizdead() */ + if (!u.udg_cnt || u.udg_cnt > soon) u.udg_cnt = soon; } else { /* at least one artifact not prepared properly */ You("have a feeling that %s is amiss...", something); goto raise_dead; @@ -282,9 +322,16 @@ /* JDS: lenses give 50% faster reading; 33% smaller read time */ if (delay && ublindf && ublindf->otyp == LENSES && rn2(2)) delay++; + if (Confusion) { /* became confused while learning */ + (void) confused_book(book); + book = 0; /* no longer studying */ + nomul(delay); /* remaining delay is uninterrupted */ + delay = 0; + return(0); + } if (delay) { /* not if (delay++), so at end delay == 0 */ - delay++; - return(1); /* still busy */ + delay++; + return(1); /* still busy */ } exercise(A_WIS, TRUE); /* you're studying. */ booktype = book->otyp; @@ -328,7 +375,11 @@ if (i == MAXSPELL) impossible("Too many spells memorized!"); if (book->cursed) { /* maybe a demon cursed it */ - cursed_book(objects[booktype].oc_level); + if (cursed_book(book)) { + useup(book); + book = 0; + return 0; + } } if (costly) check_unpaid(book); book = 0; @@ -343,7 +394,7 @@ register boolean confused = (Confusion != 0); boolean too_hard = FALSE; - if (delay && spellbook == book && + if (delay && !confused && spellbook == book && /* handle the sequence: start reading, get interrupted, have book become erased somehow, resume reading it */ booktype != SPE_BLANK_PAPER) { @@ -391,7 +442,8 @@ - 2*objects[booktype].oc_level + ((ublindf && ublindf->otyp == LENSES) ? 2 : 0); /* only wizards know if a spell is too difficult */ - if (Role_if(PM_WIZARD) && read_ability < 20) { + if (Role_if(PM_WIZARD) && read_ability < 20 && + !confused) { char qbuf[QBUFSZ]; Sprintf(qbuf, "This spellbook is %sdifficult to comprehend. Continue?", @@ -409,11 +461,12 @@ } if (too_hard) { - cursed_book(objects[booktype].oc_level); + boolean gone = cursed_book(spellbook); + nomul(delay); /* study time */ delay = 0; - if(!rn2(3)) { - pline_The("spellbook crumbles to dust!"); + if(gone || !rn2(3)) { + if (!gone) pline_The("spellbook crumbles to dust!"); if (!objects[spellbook->otyp].oc_name_known && !objects[spellbook->otyp].oc_uname) docall(spellbook); @@ -422,24 +475,12 @@ spellbook->in_use = FALSE; return(1); } else if (confused) { - if (!rn2(3) && - spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { - pline( - "Being confused you have difficulties in controlling your actions."); - display_nhwindow(WIN_MESSAGE, FALSE); - You("accidentally tear the spellbook to pieces."); - if (!objects[spellbook->otyp].oc_name_known && - !objects[spellbook->otyp].oc_uname) - docall(spellbook); - useup(spellbook); - } else { - You( - "find yourself reading the first line over and over again."); - spellbook->in_use = FALSE; - } - nomul(delay); - delay = 0; - return(1); + if (!confused_book(spellbook)) { + spellbook->in_use = FALSE; + } + nomul(delay); + delay = 0; + return(1); } spellbook->in_use = FALSE; @@ -617,7 +658,7 @@ if (gain > 0) { if (!Blind) { - const char *hgolden = hcolor(golden); + const char *hgolden = hcolor(NH_GOLDEN); if (u.uspellprot) pline_The("%s haze around you becomes more dense.", @@ -639,6 +680,35 @@ } } +/* attempting to cast a forgotten spell will cause disorientation */ +STATIC_OVL void +spell_backfire(spell) +int spell; +{ + long duration = (long)((spellev(spell) + 1) * 3); /* 6..24 */ + + /* prior to 3.4.1, the only effect was confusion; it still predominates */ + switch (rn2(10)) { + case 0: + case 1: + case 2: + case 3: make_confused(duration, FALSE); /* 40% */ + break; + case 4: + case 5: + case 6: make_confused(2L * duration / 3L, FALSE); /* 30% */ + make_stunned(duration / 3L, FALSE); + break; + case 7: + case 8: make_stunned(2L * duration / 3L, FALSE); /* 20% */ + make_confused(duration / 3L, FALSE); + break; + case 9: make_stunned(duration, FALSE); /* 10% */ + break; + } + return; +} + int spelleffects(spell, atme) int spell; @@ -657,7 +727,7 @@ if (spellknow(spell) <= 0) { Your("knowledge of this spell is twisted."); pline("It invokes nightmarish images in your mind..."); - make_confused((long)spellev(spell) * 3, FALSE); + spell_backfire(spell); return(0); } else if (spellknow(spell) <= 100) { You("strain to recall the spell."); @@ -807,7 +877,10 @@ case SPE_STONE_TO_FLESH: if (!(objects[pseudo->otyp].oc_dir == NODIR)) { if (atme) u.dx = u.dy = u.dz = 0; - else (void) getdir((char *)0); + else if (!getdir((char *)0)) { + /* getdir cancelled, re-use previous direction */ + pline_The("magical energy is released!"); + } if(!u.dx && !u.dy && !u.dz) { if ((damage = zapyourself(pseudo, TRUE)) != 0) { char buf[BUFSZ]; @@ -884,8 +957,7 @@ } /* gain skill for successful cast */ - if (role_skill != P_ISRESTRICTED && role_skill < P_EXPERT) - use_skill(skill, spellev(spell)); + use_skill(skill, spellev(spell)); obfree(pseudo, (struct obj *)0); /* now, get rid of it */ return(1); @@ -1001,7 +1073,7 @@ Sprintf(buf, "%-20s Level %-12s Fail", " Name", "Category"); else Sprintf(buf, "Name\tLevel\tCategory\tFail"); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED); for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) { Sprintf(buf, iflags.menu_tab_sep ? "%s\t%-d%s\t%s\t%-d%%" : "%-20s %2d%s %-12s %3d%%", diff -Naurd ../nethack-3.4.0/src/steal.c ./src/steal.c --- ../nethack-3.4.0/src/steal.c Wed Mar 20 23:43:18 2002 +++ ./src/steal.c Mon Feb 24 15:25:05 2003 @@ -51,6 +51,7 @@ Monnam(mtmp), makeplural(body_part(FOOT))); if(!u.ugold || !rn2(5)) { if (!tele_restrict(mtmp)) rloc(mtmp); + /* do not set mtmp->mavenge here; gold on the floor is fair game */ monflee(mtmp, 0, FALSE, FALSE); } } else if(u.ugold) { @@ -58,6 +59,7 @@ Your("purse feels lighter."); mtmp->mgold += tmp; if (!tele_restrict(mtmp)) rloc(mtmp); + mtmp->mavenge = 1; monflee(mtmp, 0, FALSE, FALSE); flags.botl = 1; } @@ -157,6 +159,8 @@ freeinv(otmp); pline("%s steals %s!", Monnam(mtmp), doname(otmp)); (void) mpickobj(mtmp,otmp); /* may free otmp */ + /* Implies seduction, "you gladly hand over ..." + so we don't set mavenge bit here. */ monflee(mtmp, 0, FALSE, FALSE); if (!tele_restrict(mtmp)) rloc(mtmp); break; @@ -172,8 +176,9 @@ /* An object you're wearing has been taken off by a monster (theft or seduction). Also used if a worn item gets transformed (stone to flesh). */ void -remove_worn_item(obj) +remove_worn_item(obj, unchain_ball) struct obj *obj; +boolean unchain_ball; /* whether to unpunish or just unwield */ { if (donning(obj)) cancel_don(); @@ -198,19 +203,21 @@ Ring_gone(obj); } else if (obj->owornmask & W_TOOL) { Blindf_off(obj); - } else if (obj->owornmask & (W_BALL|W_CHAIN)) { - unpunish(); } else if (obj->owornmask & (W_WEP|W_SWAPWEP|W_QUIVER)) { if (obj == uwep) uwepgone(); - else if (obj == uswapwep) + if (obj == uswapwep) uswapwepgone(); - else if (obj == uquiver) + if (obj == uquiver) uqwepgone(); } - /* catchall */ - if (obj->owornmask) setnotworn(obj); + if (obj->owornmask & (W_BALL|W_CHAIN)) { + if (unchain_ball) unpunish(); + } else if (obj->owornmask) { + /* catchall */ + setnotworn(obj); + } } /* Returns 1 when something was stolen (or at least, when N should flee now) @@ -306,7 +313,7 @@ ostuck = (otmp->cursed && otmp->owornmask); if (ostuck || !can_carry(mtmp, otmp)) { - static const char *how[] = { "steal","snatch","grab","take" }; + static const char * const how[] = { "steal","snatch","grab","take" }; cant_take: pline("%s tries to %s your %s but gives up.", Monnam(mtmp), how[rn2(SIZE(how))], @@ -333,23 +340,24 @@ case AMULET_CLASS: case RING_CLASS: case FOOD_CLASS: /* meat ring */ - remove_worn_item(otmp); + remove_worn_item(otmp, TRUE); break; case ARMOR_CLASS: armordelay = objects[otmp->otyp].oc_delay; /* Stop putting on armor which has been stolen. */ if (donning(otmp)) { - remove_worn_item(otmp); + remove_worn_item(otmp, TRUE); break; } else if (monkey_business) { /* animals usually don't have enough patience to take off items which require extra time */ if (armordelay >= 1 && rn2(10)) goto cant_take; - remove_worn_item(otmp); + remove_worn_item(otmp, TRUE); break; } else { int curssv = otmp->cursed; int slowly; + boolean seen = canspotmon(mtmp); otmp->cursed = 0; /* can't charm you without first waking you */ @@ -357,20 +365,20 @@ slowly = (armordelay >= 1 || multi < 0); if(flags.female) pline("%s charms you. You gladly %s your %s.", - Blind ? "She" : Monnam(mtmp), + !seen ? "She" : Monnam(mtmp), curssv ? "let her take" : slowly ? "start removing" : "hand over", equipname(otmp)); else pline("%s seduces you and %s off your %s.", - Blind ? "It" : Adjmonnam(mtmp, "beautiful"), + !seen ? "She" : Adjmonnam(mtmp, "beautiful"), curssv ? "helps you to take" : slowly ? "you start taking" : "you take", equipname(otmp)); named++; /* the following is to set multi for later on */ nomul(-armordelay); - remove_worn_item(otmp); + remove_worn_item(otmp, TRUE); otmp->cursed = curssv; if(multi < 0){ /* @@ -391,10 +399,14 @@ } } else if (otmp->owornmask) - remove_worn_item(otmp); + remove_worn_item(otmp, TRUE); /* do this before removing it from inventory */ if (objnambuf) Strcpy(objnambuf, yname(otmp)); + /* set mavenge bit so knights won't suffer an + * alignment penalty during retaliation; + */ + mtmp->mavenge = 1; freeinv(otmp); pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp)); @@ -420,7 +432,7 @@ int freed_otmp; #ifndef GOLDOBJ - if (otmp->oclass == GOLD_CLASS) { + if (otmp->oclass == COIN_CLASS) { mtmp->mgold += otmp->quan; obfree(otmp, (struct obj *)0); freed_otmp = 1; @@ -487,7 +499,7 @@ if (otmp) { /* we have something to snatch */ if (otmp->owornmask) - remove_worn_item(otmp); + remove_worn_item(otmp, TRUE); freeinv(otmp); /* mpickobj wont merge otmp because none of the above things to steal are mergable */ @@ -543,6 +555,11 @@ costly_spot(mtmp->mx, mtmp->my)) otmp->no_charge = 1; #endif + if (otmp->owornmask) + update_mon_intrinsics(mtmp, otmp, FALSE, TRUE); + /* obj_no_longer_held(otmp); -- done by place_object */ + if (otmp->owornmask & W_WEP) + setmnotwielded(mtmp, otmp); otmp->owornmask = 0L; } if (is_pet && cansee(omx, omy) && flags.verbose) diff -Naurd ../nethack-3.4.0/src/steed.c ./src/steed.c --- ../nethack-3.4.0/src/steed.c Wed Mar 20 23:43:18 2002 +++ ./src/steed.c Mon Feb 24 15:25:05 2003 @@ -14,6 +14,13 @@ STATIC_DCL boolean FDECL(landing_spot, (coord *, int)); +/* caller has decided that hero can't reach something while mounted */ +void +rider_cant_reach() +{ + You("aren't skilled enough to reach from %s.", y_monnam(u.usteed)); +} + /*** Putting the saddle on ***/ /* Can this monster wear a saddle? */ @@ -132,6 +139,7 @@ /* Make the attempt */ if (rn2(100) < chance) { You("put the saddle on %s.", mon_nam(mtmp)); + if (otmp->owornmask) remove_worn_item(otmp, FALSE); freeinv(otmp); /* mpickobj may free otmp it if merges, but we have already checked for a saddle above, so no merger should happen */ @@ -139,7 +147,7 @@ mtmp->misc_worn_check |= W_SADDLE; otmp->owornmask = W_SADDLE; otmp->leashmon = mtmp->m_id; - update_mon_intrinsics(mtmp, otmp, TRUE); + update_mon_intrinsics(mtmp, otmp, TRUE, FALSE); } else pline("%s resists!", Monnam(mtmp)); return 1; @@ -188,11 +196,9 @@ char buf[BUFSZ]; struct permonst *ptr; - /* Sanity checks */ if (u.usteed) { - if (!force) - You("are already riding %s.", mon_nam(u.usteed)); + You("are already riding %s.", mon_nam(u.usteed)); return (FALSE); } @@ -220,11 +226,10 @@ #endif return (FALSE); } - + if (Upolyd && (!humanoid(youmonst.data) || verysmall(youmonst.data) || - bigmonst(youmonst.data))) { - if (!force) - You("won't fit on a saddle."); + bigmonst(youmonst.data) || slithy(youmonst.data))) { + You("won't fit on a saddle."); return (FALSE); } if(!force && (near_capacity() > SLT_ENCUMBER)) { @@ -233,22 +238,19 @@ } /* Can the player reach and see the monster? */ - if (u.uswallow || u.ustuck || u.utrap || Punished) { - if (!force) { - if (Punished) - You("are unable to swing your %s over.", - body_part(LEG)); - else - You("are stuck here for now."); - } - return (FALSE); - } if (!mtmp || (!force && ((Blind && !Blind_telepat) || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT))) { - if (!force) - pline("I see nobody there."); + pline("I see nobody there."); + return (FALSE); + } + if (u.uswallow || u.ustuck || u.utrap || Punished || + !test_move(u.ux, u.uy, mtmp->mx-u.ux, mtmp->my-u.uy, TEST_MOVE)) { + if (Punished || !(u.uswallow || u.ustuck || u.utrap)) + You("are unable to swing your %s over.", body_part(LEG)); + else + You("are stuck here for now."); return (FALSE); } @@ -263,14 +265,22 @@ char kbuf[BUFSZ]; You("touch %s.", mon_nam(mtmp)); - Sprintf(kbuf, "attempting to ride %s", an(mtmp->data->mname)); + Sprintf(kbuf, "attempting to ride %s", an(mtmp->data->mname)); instapetrify(kbuf); } if (!mtmp->mtame || mtmp->isminion) { - if (!force) - pline("I think %s would mind.", mon_nam(mtmp)); + pline("I think %s would mind.", mon_nam(mtmp)); return (FALSE); } + if (mtmp->mtrapped) { + struct trap *t = t_at(mtmp->mx, mtmp->my); + + You_cant("mount %s while %s's trapped in %s.", + mon_nam(mtmp), mhe(mtmp), + an(defsyms[trap_to_defsym(t->ttyp)].explanation)); + return (FALSE); + } + if (!force && !Role_if(PM_KNIGHT) && !(--mtmp->mtame)) { /* no longer tame */ newsym(mtmp->mx, mtmp->my); @@ -284,8 +294,7 @@ return (FALSE); } if (!can_saddle(mtmp) || !can_ride(mtmp)) { - if (!force) - You_cant("ride such a creature."); + You_cant("ride such a creature."); return (0); } @@ -310,15 +319,11 @@ } You("slip while trying to get on %s.", mon_nam(mtmp)); - /* Unfortunately we don't have a version of the monster-naming - * function that works well with "a" and "the" but ignores - * hallucination. Fortunately, we know the monster must be saddled - * at this point, and that it can't have type_is_pname(), so we - * don't need to worry about the special cases such a function - * would have to consider. - */ - Sprintf(buf, "slipped while mounting a saddled %s", - m_monnam(mtmp)); + Sprintf(buf, "slipped while mounting %s", + /* "a saddled mumak" or "a saddled pony called Dobbin" */ + x_monnam(mtmp, ARTICLE_A, (char *)0, + SUPPRESS_IT|SUPPRESS_INVISIBLE|SUPPRESS_HALLUCINATION, + TRUE)); losehp(rn1(5,10), buf, NO_KILLER_PREFIX); return (FALSE); } @@ -330,9 +335,11 @@ pline("%s magically floats up!", Monnam(mtmp)); You("mount %s.", mon_nam(mtmp)); } + /* setuwep handles polearms differently when you're mounted */ + if (uwep && is_pole(uwep)) unweapon = FALSE; u.usteed = mtmp; remove_monster(mtmp->mx, mtmp->my); - teleds(mtmp->mx, mtmp->my); + teleds(mtmp->mx, mtmp->my, TRUE); return (TRUE); } @@ -486,7 +493,8 @@ case DISMOUNT_BYCHOICE: default: if (otmp && otmp->cursed) { - You("can't. The saddle seems to be cursed."); + You("can't. The saddle %s cursed.", + otmp->bknown ? "is" : "seems to be"); otmp->bknown = TRUE; return; } @@ -568,7 +576,7 @@ * teleds() clears u.utrap */ in_steed_dismounting = TRUE; - teleds(cc.x, cc.y); + teleds(cc.x, cc.y, TRUE); in_steed_dismounting = FALSE; /* Put your steed in your trap */ @@ -588,14 +596,17 @@ } /* Return the player to the floor */ - in_steed_dismounting = TRUE; - (void) float_down(0L, W_SADDLE); - in_steed_dismounting = FALSE; - flags.botl = 1; if (reason != DISMOUNT_ENGULFED) { - (void)encumber_msg(); - vision_full_recalc = 1; - } + in_steed_dismounting = TRUE; + (void) float_down(0L, W_SADDLE); + in_steed_dismounting = FALSE; + flags.botl = 1; + (void)encumber_msg(); + vision_full_recalc = 1; + } else + flags.botl = 1; + /* polearms behave differently when not mounted */ + if (uwep && is_pole(uwep)) unweapon = TRUE; return; } diff -Naurd ../nethack-3.4.0/src/teleport.c ./src/teleport.c --- ../nethack-3.4.0/src/teleport.c Wed Mar 20 23:43:18 2002 +++ ./src/teleport.c Mon Feb 24 15:25:05 2003 @@ -18,11 +18,13 @@ * call it to generate new monster positions with fake monster structures. */ boolean -goodpos(x, y, mtmp) +goodpos(x, y, mtmp, gpflags) int x,y; struct monst *mtmp; +unsigned gpflags; { struct permonst *mdat = NULL; + boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0); if (!isok(x, y)) return FALSE; @@ -42,17 +44,27 @@ if (mtmp) { struct monst *mtmp2 = m_at(x,y); - if (mtmp2 && mtmp2 != mtmp) + /* Be careful with long worms. A monster may be placed back in + * its own location. Normally, if m_at() returns the same monster + * that we're trying to place, the monster is being placed in its + * own location. However, that is not correct for worm segments, + * because all the segments of the worm return the same m_at(). + * Actually we overdo the check a little bit--a worm can't be placed + * in its own location, period. If we just checked for mtmp->mx + * != x || mtmp->my != y, we'd miss the case where we're called + * to place the worm segment and the worm's head is at x,y. + */ + if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno)) return FALSE; mdat = mtmp->data; - if (is_pool(x,y)) { + if (is_pool(x,y) && !ignorewater) { if (mtmp == &youmonst) return !!(HLevitation || Flying || Wwalking || Swimming || Amphibious); else return (is_flyer(mdat) || is_swimmer(mdat) || is_clinger(mdat)); - } else if (mdat->mlet == S_EEL && rn2(13)) { + } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) { return FALSE; } else if (is_lava(x,y)) { if (mtmp == &youmonst) @@ -62,7 +74,10 @@ } if (passes_walls(mdat) && may_passwall(x,y)) return TRUE; } - if (!ACCESSIBLE(levl[x][y].typ)) return FALSE; + if (!ACCESSIBLE(levl[x][y].typ)) { + if (!(is_pool(x,y) && ignorewater)) return FALSE; + } + if (closed_door(x, y) && (!mdat || !amorphous(mdat))) return FALSE; if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat))) @@ -84,6 +99,16 @@ register xchar xx, yy; struct permonst *mdat; { + return enexto_core(cc, xx, yy, mdat, 0); +} + +boolean +enexto_core(cc, xx, yy, mdat, entflags) +coord *cc; +register xchar xx, yy; +struct permonst *mdat; +unsigned entflags; +{ #define MAX_GOOD 15 coord good[MAX_GOOD], *good_ptr; int x, y, range, i; @@ -111,28 +136,28 @@ ymax = min(ROWNO-1, yy+range); for (x = xmin; x <= xmax; x++) - if (goodpos(x, ymin, &fakemon)) { + if (goodpos(x, ymin, &fakemon, entflags)) { good_ptr->x = x; good_ptr->y = ymin ; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD-1]) goto full; } for (x = xmin; x <= xmax; x++) - if (goodpos(x, ymax, &fakemon)) { + if (goodpos(x, ymax, &fakemon, entflags)) { good_ptr->x = x; good_ptr->y = ymax ; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD-1]) goto full; } for (y = ymin+1; y < ymax; y++) - if (goodpos(xmin, y, &fakemon)) { + if (goodpos(xmin, y, &fakemon, entflags)) { good_ptr->x = xmin; good_ptr-> y = y ; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD-1]) goto full; } for (y = ymin+1; y < ymax; y++) - if (goodpos(xmax, y, &fakemon)) { + if (goodpos(xmax, y, &fakemon, entflags)) { good_ptr->x = xmax; good_ptr->y = y ; /* beware of accessing beyond segment boundaries.. */ @@ -195,40 +220,58 @@ boolean trapok; { if (!trapok && t_at(x, y)) return FALSE; - if (!goodpos(x, y, &youmonst)) return FALSE; + if (!goodpos(x, y, &youmonst, 0)) return FALSE; if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE; + if (!in_out_region(x, y)) return FALSE; return TRUE; } void -teleds(nux, nuy) +teleds(nux, nuy, allow_drag) register int nux,nuy; +boolean allow_drag; { - boolean dont_teleport_ball = FALSE; + boolean ball_active = (Punished && uball->where != OBJ_FREE), + ball_still_in_range = FALSE; - if (Punished) { - /* If they're teleporting to a position where the ball doesn't need - * to be moved, don't place the ball. Especially useful when this - * function is being called for crawling out of water instead of - * real teleportation. - */ + /* If they have to move the ball, then drag if allow_drag is true; + * otherwise they are teleporting, so unplacebc(). + * If they don't have to move the ball, then always "drag" whether or + * not allow_drag is true, because we are calling that function, not + * to drag, but to move the chain. *However* there are some dumb + * special cases: + * 0 0 + * _X move east -----> X_ + * @ @ + * These are permissible if teleporting, but not if dragging. As a + * result, drag_ball() needs to know about allow_drag and might end + * up dragging the ball anyway. Also, drag_ball() might find that + * dragging the ball is completely impossible (ball in range but there's + * rock in the way), in which case it teleports the ball on its own. + */ + if (ball_active) { if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2) - dont_teleport_ball = TRUE; - else - unplacebc(); + ball_still_in_range = TRUE; /* don't have to move the ball */ + else { + /* have to move the ball */ + if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) { + /* we should not have dist > 1 and allow_drag at the same + * time, but just in case, we must then revert to teleport. + */ + allow_drag = FALSE; + unplacebc(); + } + } } u.utrap = 0; u.ustuck = 0; u.ux0 = u.ux; u.uy0 = u.uy; - u.ux = nux; - u.uy = nuy; - fill_pit(u.ux0, u.uy0); /* do this now so that cansee() is correct */ if (hides_under(youmonst.data)) u.uundetected = OBJ_AT(nux, nuy); else if (youmonst.data->mlet == S_EEL) - u.uundetected = is_pool(u.ux, u.uy); + u.uundetected = is_pool(nux, nuy); else { u.uundetected = 0; /* mimics stop being unnoticed */ @@ -238,21 +281,32 @@ if (u.uswallow) { u.uswldtim = u.uswallow = 0; + if (Punished && !ball_active) { + /* ensure ball placement, like unstuck */ + ball_active = TRUE; + allow_drag = FALSE; + } docrt(); } - if (Punished) { - if (dont_teleport_ball) { + if (ball_active) { + if (ball_still_in_range || allow_drag) { int bc_control; xchar ballx, bally, chainx, chainy; boolean cause_delay; - /* this should only drag the chain (and never give a near- - capacity message) since we already checked ball distance */ - (void) drag_ball(u.ux, u.uy, &bc_control, &ballx, &bally, - &chainx, &chainy, &cause_delay); - move_bc(0, bc_control, ballx, bally, chainx, chainy); - } else - placebc(); + if (drag_ball(nux, nuy, &bc_control, &ballx, &bally, + &chainx, &chainy, &cause_delay, allow_drag)) + move_bc(0, bc_control, ballx, bally, chainx, chainy); + } + } + /* must set u.ux, u.uy after drag_ball(), which may need to know + the old position if allow_drag is true... */ + u.ux = nux; + u.uy = nuy; + fill_pit(u.ux0, u.uy0); + if (ball_active) { + if (!ball_still_in_range && !allow_drag) + placebc(); } initrack(); /* teleports mess up tracking monsters without this */ update_player_regions(); @@ -279,7 +333,8 @@ } boolean -safe_teleds() +safe_teleds(allow_drag) +boolean allow_drag; { register int nux, nuy, tcnt = 0; @@ -289,7 +344,7 @@ } while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400); if (tcnt <= 400) { - teleds(nux, nuy); + teleds(nux, nuy, allow_drag); return TRUE; } else return FALSE; @@ -302,7 +357,7 @@ coord c; if (croom && somexy(croom, &c) && teleok(c.x,c.y,FALSE)) { - teleds(c.x,c.y); + teleds(c.x,c.y,FALSE); return; } tele(); @@ -363,7 +418,7 @@ You_feel("disoriented for a moment."); return; } - if (Teleport_control + if ((Teleport_control && !Stunned) #ifdef WIZARD || wizard #endif @@ -387,14 +442,14 @@ /* possible extensions: introduce a small error if magic power is low; allow transfer to solid rock */ if (teleok(cc.x, cc.y, FALSE)) { - teleds(cc.x, cc.y); + teleds(cc.x, cc.y, FALSE); return; } pline("Sorry..."); } } - (void) safe_teleds(); + (void) safe_teleds(FALSE); } int @@ -521,7 +576,7 @@ You_feel("very disoriented for a moment."); return; } - if (Teleport_control + if ((Teleport_control && !Stunned) #ifdef WIZARD || wizard #endif @@ -533,10 +588,18 @@ do { if (++trycnt == 2) Strcat(qbuf, " [type a number]"); getlin(qbuf, buf); - if (!strcmp(buf,"\033")) /* cancelled */ + if (!strcmp(buf,"\033")) { /* cancelled */ + if (Confusion && rnl(5)) { + pline("Oops..."); + goto random_levtport; + } return; - else if (!strcmp(buf,"*")) + } else if (!strcmp(buf,"*")) { goto random_levtport; + } else if (Confusion && rnl(5)) { + pline("Oops..."); + goto random_levtport; + } if ((newlev = lev_by_name(buf)) == 0) newlev = atoi(buf); } while (!newlev && !digit(buf[0]) && (buf[0] != '-' || !digit(buf[1])) && @@ -605,6 +668,14 @@ killer = 0; /* still alive, so far... */ if (newlev < 0) { + if (*u.ushops0) { + /* take unpaid inventory items off of shop bills */ + in_mklev = TRUE; /* suppress map update */ + u_left_shop(u.ushops0, TRUE); + /* you're now effectively out of the shop */ + *u.ushops0 = *u.ushops = '\0'; + in_mklev = FALSE; + } if (newlev <= -10) { You("arrive in heaven."); verbalize("Thou art early, but we'll admit thee."); @@ -627,8 +698,8 @@ pline("Unfortunately, you don't know how to fly."); You("plummet a few thousand feet to your death."); Sprintf(buf, - "teleported out of the dungeon and fell to %s death", - uhis()); + "teleported out of the dungeon and fell to %s death", + uhis()); killer = buf; killer_format = NO_KILLER_PREFIX; } @@ -770,7 +841,7 @@ { register int xx, yy; - if (!goodpos(x, y, mtmp)) return FALSE; + if (!goodpos(x, y, mtmp, 0)) return FALSE; /* * Check for restricted areas present in some special levels. * @@ -882,7 +953,7 @@ /* if the wiz teleports away to heal, try the up staircase, to block the player's escaping before he's healed (deliberately use `goodpos' rather than `rloc_pos_ok' here) */ - if (goodpos(x, y, mtmp)) + if (goodpos(x, y, mtmp, 0)) goto found_xy; } @@ -891,14 +962,14 @@ x = rn1(COLNO-3,2); y = rn2(ROWNO); if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp) - : goodpos(x, y, mtmp)) + : goodpos(x, y, mtmp, 0)) goto found_xy; } while (++trycount < 1000); /* last ditch attempt to find a good place */ for (x = 2; x < COLNO - 1; x++) for (y = 0; y < ROWNO; y++) - if (goodpos(x, y, mtmp)) + if (goodpos(x, y, mtmp, 0)) goto found_xy; /* level either full of monsters or somehow faulty */ @@ -917,7 +988,7 @@ coord c; if (croom && somexy(croom, &c) && - goodpos(c.x, c.y, mtmp)) { + goodpos(c.x, c.y, mtmp, 0)) { rloc_to(mtmp, c.x, c.y); return; } @@ -1058,7 +1129,7 @@ tx = rn1(COLNO-3,2); ty = rn2(ROWNO); if (!--try_limit) break; - } while (!goodpos(tx, ty, (struct monst *)0) || + } while (!goodpos(tx, ty, (struct monst *)0, 0) || /* bug: this lacks provision for handling the Wizard's tower */ (restricted_fall && (!within_bounded_area(tx, ty, dndest.lx, dndest.ly, diff -Naurd ../nethack-3.4.0/src/timeout.c ./src/timeout.c --- ../nethack-3.4.0/src/timeout.c Wed Mar 20 23:43:19 2002 +++ ./src/timeout.c Mon Feb 24 15:25:05 2003 @@ -17,7 +17,7 @@ #ifdef OVLB /* He is being petrified - dialogue by inmet!tower */ -static NEARDATA const char *stoned_texts[] = { +static NEARDATA const char * const stoned_texts[] = { "You are slowing down.", /* 5 */ "Your limbs are stiffening.", /* 4 */ "Your limbs have turned to stone.", /* 3 */ @@ -40,8 +40,8 @@ } /* He is getting sicker and sicker prior to vomiting */ -static NEARDATA const char *vomiting_texts[] = { - "are feeling mildly nauseous.", /* 14 */ +static NEARDATA const char * const vomiting_texts[] = { + "are feeling mildly nauseated.", /* 14 */ "feel slightly confused.", /* 11 */ "can't seem to think straight.", /* 8 */ "feel incredibly sick.", /* 5 */ @@ -72,7 +72,7 @@ exercise(A_CON, FALSE); } -static NEARDATA const char *choke_texts[] = { +static NEARDATA const char * const choke_texts[] = { "You find it hard to breathe.", "You're gasping for air.", "You can no longer breathe.", @@ -80,7 +80,7 @@ "You suffocate." }; -static NEARDATA const char *choke_texts2[] = { +static NEARDATA const char * const choke_texts2[] = { "Your %s is becoming constricted.", "Your blood is having trouble reaching your brain.", "The pressure on your %s increases.", @@ -100,7 +100,7 @@ const char *str = choke_texts[SIZE(choke_texts)-i]; if (index(str, '%')) - pline(str, hcolor(blue)); + pline(str, hcolor(NH_BLUE)); else pline(str); } @@ -108,7 +108,7 @@ exercise(A_STR, FALSE); } -static NEARDATA const char *slime_texts[] = { +static NEARDATA const char * const slime_texts[] = { "You are turning a little %s.", /* 5 */ "Your limbs are getting oozy.", /* 4 */ "Your skin begins to peel away.", /* 3 */ @@ -128,7 +128,7 @@ if (index(str, '%')) { if (i == 4L) { /* "you are turning green" */ if (!Blind) /* [what if you're already green?] */ - pline(str, hcolor(green)); + pline(str, hcolor(NH_GREEN)); } else pline(str, an(Hallucination ? rndmonnam() : "green slime")); } else @@ -202,7 +202,7 @@ u.uspellprot--; find_ac(); if (!Blind) - Norep("The %s haze around you %s.", hcolor(golden), + Norep("The %s haze around you %s.", hcolor(NH_GOLDEN), u.uspellprot ? "becomes less dense" : "disappears"); } } @@ -287,10 +287,11 @@ break; case INVIS: newsym(u.ux,u.uy); - if (!Invis && !BInvis && - !See_invisible && !Blind) { - You("are no longer invisible."); - stop_occupation(); + if (!Invis && !BInvis && !Blind) { + You(!See_invisible ? + "are no longer invisible." : + "can no longer see through yourself."); + stop_occupation(); } break; case SEE_INVIS: @@ -367,6 +368,13 @@ { stop_occupation(); nomul(how_long); + /* generally don't notice sounds while sleeping */ + if (wakeup_msg && multi == how_long) { + /* caller can follow with a direct call to Hear_again() if + there's a need to override this when wakeup_msg is true */ + flags.soundok = 0; + afternmv = Hear_again; /* this won't give any messages */ + } /* early wakeup from combat won't be possible until next monster turn */ u.usleep = monstermoves; nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again; @@ -621,6 +629,8 @@ if (u.usteed) on_foot = FALSE; #endif + if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy)) otmp = 0; + if (otmp && on_foot) { /* trip over something in particular */ /* If there is only one item, it will have just been named @@ -1307,7 +1317,7 @@ } ttable; /* table of timeout functions */ -static ttable timeout_funcs[NUM_TIME_FUNCS] = { +static const ttable timeout_funcs[NUM_TIME_FUNCS] = { TTAB(rot_organic, (timeout_proc)0, "rot_organic"), TTAB(rot_corpse, (timeout_proc)0, "rot_corpse"), TTAB(revive_mon, (timeout_proc)0, "revive_mon"), diff -Naurd ../nethack-3.4.0/src/topten.c ./src/topten.c --- ../nethack-3.4.0/src/topten.c Wed Mar 20 23:43:19 2002 +++ ./src/topten.c Mon Feb 24 15:25:05 2003 @@ -76,9 +76,9 @@ #endif /* must fit with end.c; used in rip.c */ -NEARDATA const char *killed_by_prefix[] = { +NEARDATA const char * const killed_by_prefix[] = { "killed by ", "choked on ", "poisoned by ", "", "drowned in ", - "", "dissolved in ", "crushed to death by ", "petrified by ", + "burned by ", "dissolved in ", "crushed to death by ", "petrified by ", "turned to slime by ", "killed by ", "", "", "", "", "" }; @@ -128,13 +128,13 @@ struct toptenentry *tt; { #ifdef NO_SCAN_BRACK /* Version_ Pts DgnLevs_ Hp___ Died__Born id */ - static const char *fmt = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c"; - static const char *fmt32 = "%c%c %s %s%*c"; - static const char *fmt33 = "%s %s %s %s %s %s%*c"; + static const char fmt[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c"; + static const char fmt32[] = "%c%c %s %s%*c"; + static const char fmt33[] = "%s %s %s %s %s %s%*c"; #else - static const char *fmt = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d "; - static const char *fmt32 = "%c%c %[^,],%[^\n]%*c"; - static const char *fmt33 = "%s %s %s %s %[^,],%[^\n]%*c"; + static const char fmt[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d "; + static const char fmt32[] = "%c%c %[^,],%[^\n]%*c"; + static const char fmt33[] = "%s %s %s %s %[^,],%[^\n]%*c"; #endif #ifdef UPDATE_RECORD_IN_PLACE @@ -340,7 +340,7 @@ #ifdef LOGFILE /* used for debugging (who dies of what, where) */ if (lock_file(LOGFILE, SCOREPREFIX, 10)) { - if(!(lfile = fopen_datafile(LOGFILE, "a", TRUE))) { + if(!(lfile = fopen_datafile(LOGFILE, "a", SCOREPREFIX))) { HUP raw_print("Cannot open log file!"); } else { writeentry(lfile, t0); @@ -366,9 +366,9 @@ goto destroywin; #ifdef UPDATE_RECORD_IN_PLACE - rfile = fopen_datafile(RECORD, "r+", TRUE); + rfile = fopen_datafile(RECORD, "r+", SCOREPREFIX); #else - rfile = fopen_datafile(RECORD, "r", TRUE); + rfile = fopen_datafile(RECORD, "r", SCOREPREFIX); #endif if (!rfile) { @@ -445,7 +445,7 @@ t0->fpos : final_fpos), SEEK_SET); #else (void) fclose(rfile); - if(!(rfile = fopen_datafile(RECORD, "w", TRUE))){ + if(!(rfile = fopen_datafile(RECORD, "w", SCOREPREFIX))){ HUP raw_print("Cannot write record file"); unlock_file(RECORD); free_ttlist(tt_head); @@ -629,8 +629,9 @@ } Sprintf(eos(linebuf), fmt, arg); } else { - Sprintf(eos(linebuf), " in %s on level %d", - dungeons[t1->deathdnum].dname, t1->deathlev); + Sprintf(eos(linebuf), " in %s", dungeons[t1->deathdnum].dname); + if (t1->deathdnum != knox_level.dnum) + Sprintf(eos(linebuf), " on level %d", t1->deathlev); if (t1->deathlev != t1->maxlvl) Sprintf(eos(linebuf), " [max %d]", t1->maxlvl); } @@ -762,7 +763,7 @@ return; } - rfile = fopen_datafile(RECORD, "r", TRUE); + rfile = fopen_datafile(RECORD, "r", SCOREPREFIX); if (!rfile) { raw_print("Cannot open record file!"); return; @@ -787,14 +788,6 @@ if (!argv[1][2]){ /* plain "-s" */ argc--; argv++; -#if 0 /* uses obsolete pl_classes[] */ - } else if (!argv[1][3] && index(pl_classes, argv[1][2])) { - /* may get this case instead of next accidentally, - * but neither is listed in the documentation, so - * anything useful that happens is a bonus anyway */ - argv[1]++; - argv[1][0] = '-'; -#endif } else argv[1] += 2; if (argc > 1 && !strcmp(argv[1], "-v")) { @@ -856,6 +849,12 @@ else { if (playerct > 1) Strcat(pbuf, "any of "); for (i = 0; i < playerct; i++) { + /* stop printing players if there are too many to fit */ + if (strlen(pbuf) + strlen(players[i]) + 2 >= BUFSZ) { + if (strlen(pbuf) < BUFSZ-4) Strcat(pbuf, "..."); + else Strcpy(pbuf+strlen(pbuf)-4, "..."); + break; + } Strcat(pbuf, players[i]); if (i < playerct-1) { if (players[i][0] == '-' && @@ -922,7 +921,7 @@ if (!otmp) return((struct obj *) 0); - rfile = fopen_datafile(RECORD, "r", TRUE); + rfile = fopen_datafile(RECORD, "r", SCOREPREFIX); if (!rfile) { impossible("Cannot open record file!"); return (struct obj *)0; diff -Naurd ../nethack-3.4.0/src/trap.c ./src/trap.c --- ../nethack-3.4.0/src/trap.c Wed Mar 20 23:43:19 2002 +++ ./src/trap.c Mon Feb 24 15:25:05 2003 @@ -1,10 +1,10 @@ -/* SCCS Id: @(#)trap.c 3.4 2001/09/06 */ +/* SCCS Id: @(#)trap.c 3.4 2003/02/10 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" -extern const char *destroy_strings[]; +extern const char * const destroy_strings[]; /* from zap.c */ STATIC_DCL void FDECL(dofiretrap, (struct obj *)); STATIC_DCL void NDECL(domagictrap); @@ -20,7 +20,7 @@ STATIC_DCL int FDECL(disarm_shooting_trap, (struct trap *, int)); STATIC_DCL int FDECL(try_lift, (struct monst *, struct trap *, int, BOOLEAN_P)); STATIC_DCL int FDECL(help_monster_out, (struct monst *, struct trap *)); -STATIC_DCL boolean FDECL(thitm, (int, struct monst *, struct obj *, int)); +STATIC_DCL boolean FDECL(thitm, (int,struct monst *,struct obj *,int,BOOLEAN_P)); STATIC_DCL int FDECL(mkroll_launch, (struct trap *,XCHAR_P,XCHAR_P,SHORT_P,long)); STATIC_DCL boolean FDECL(isclearpath,(coord *, int, SCHAR_P, SCHAR_P)); @@ -34,14 +34,17 @@ STATIC_VAR const char *the_your[2]; STATIC_VAR const char tower_of_flame[]; STATIC_VAR const char *A_gush_of_water_hits; +STATIC_VAR const char * const blindgas[6]; #else -STATIC_VAR const char *a_your[2] = { "a", "your" }; -STATIC_VAR const char *A_Your[2] = { "A", "Your" }; -STATIC_VAR const char *the_your[2] = { "the", "your" }; +STATIC_VAR const char * const a_your[2] = { "a", "your" }; +STATIC_VAR const char * const A_Your[2] = { "A", "Your" }; +STATIC_VAR const char * const the_your[2] = { "the", "your" }; STATIC_VAR const char tower_of_flame[] = "tower of flame"; -STATIC_VAR const char *A_gush_of_water_hits = "A gush of water hits"; +STATIC_VAR const char * const A_gush_of_water_hits = "A gush of water hits"; +STATIC_VAR const char * const blindgas[6] = + {"humid", "odorless", "pungent", "chilling", "acrid", "biting"}; #endif /* OVLB */ @@ -117,8 +120,8 @@ boolean print; struct monst *victim; { - static NEARDATA const char *action[] = { "smoulder", "rust", "rot", "corrode" }; - static NEARDATA const char *msg[] = { "burnt", "rusted", "rotten", "corroded" }; + static NEARDATA const char * const action[] = { "smoulder", "rust", "rot", "corrode" }; + static NEARDATA const char * const msg[] = { "burnt", "rusted", "rotten", "corroded" }; boolean vulnerable = FALSE; boolean grprot = FALSE; boolean is_primary = TRUE; @@ -280,9 +283,11 @@ case TRAPDOOR: lev = &levl[x][y]; if (*in_rooms(x, y, SHOPBASE) && - ((typ == HOLE || typ == TRAPDOOR) || IS_DOOR(lev->typ))) + ((typ == HOLE || typ == TRAPDOOR) || + IS_DOOR(lev->typ) || IS_WALL(lev->typ))) add_damage(x, y, /* schedule repair */ - (IS_DOOR(lev->typ) && !flags.mon_moving) ? 200L : 0L); + ((IS_DOOR(lev->typ) || IS_WALL(lev->typ)) + && !flags.mon_moving) ? 200L : 0L); lev->doormask = 0; /* subsumes altarmask, icedpool... */ if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */ lev->typ = ROOM; @@ -331,6 +336,7 @@ if(td) { struct trap *t=t_at(u.ux,u.uy); + seetrap(t); if (!In_sokoban(&u.uz)) { if (t->ttyp == TRAPDOOR) pline("A trap door opens up under you!"); @@ -403,6 +409,7 @@ struct monst *mon = 0; struct obj *item; coord cc; + boolean historic = (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && statue->spe); if (statue->oxlth && statue->oattached == OATTACHED_MONST) { cc.x = x, cc.y = y; @@ -442,12 +449,19 @@ /* mimic statue becomes seen mimic; other hiders won't be hidden */ if (mon->m_ap_type) seemimic(mon); else mon->mundetected = FALSE; - if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) - pline_The("statue comes to life!"); - else if (cause == ANIMATE_SHATTER) - pline("Instead of shattering, the statue suddenly comes alive!"); + if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) { + pline_The("statue %s!", + canspotmon(mon) ? "comes to life" : "disappears"); + if (historic) { + You_feel("guilty that the historic statue is now gone."); + adjalign(-1); + } + } else if (cause == ANIMATE_SHATTER) + pline("Instead of shattering, the statue suddenly %s!", + canspotmon(mon) ? "comes to life" : "disappears"); else /* cause == ANIMATE_NORMAL */ - You("find %s posing as a statue.", a_monnam(mon)); + You("find %s posing as a statue.", + canspotmon(mon) ? a_monnam(mon) : something); /* avoid hiding under nothing */ if (x == u.ux && y == u.uy && Upolyd && hides_under(youmonst.data) && !OBJ_AT(x, y)) @@ -538,6 +552,10 @@ } } +#ifdef STEED + if (u.usteed) u.usteed->mtrapseen |= (1 << (ttype-1)); +#endif + switch(ttype) { case ARROW_TRAP: seetrap(trap); @@ -671,9 +689,7 @@ break; } pline("A cloud of gas puts you to sleep!"); - flags.soundok = 0; fall_asleep(-rnd(25), TRUE); - afternmv = Hear_again; #ifdef STEED (void) steedintrap(trap, (struct obj *)0); #endif @@ -760,17 +776,17 @@ break; } if (!In_sokoban(&u.uz)) { - char verbbuf[BUFSZ]; + char verbbuf[BUFSZ]; #ifdef STEED - if (u.usteed) + if (u.usteed) Sprintf(verbbuf,"lead %s", x_monnam(u.usteed, u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, "poor", SUPPRESS_SADDLE, FALSE)); - else + else #endif Strcpy(verbbuf,"fall"); - You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]); + You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]); } /* wumpus reference */ if (Role_if(PM_RANGER) && !trap->madeby_u && !trap->once && @@ -781,13 +797,14 @@ u.umonnum == PM_PIT_FIEND) pline("How pitiful. Isn't that the pits?"); if (ttype == SPIKED_PIT) { - char *predicament = "on a set of sharp iron spikes"; + const char *predicament = "on a set of sharp iron spikes"; #ifdef STEED if (u.usteed) { pline("%s lands %s!", upstart(x_monnam(u.usteed, u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, - "poor", SUPPRESS_SADDLE, FALSE)), predicament); + "poor", SUPPRESS_SADDLE, FALSE)), + predicament); } else #endif You("land %s!", predicament); @@ -820,8 +837,8 @@ break; case HOLE: case TRAPDOOR: - seetrap(trap); if (!Can_fall_thru(&u.uz)) { + seetrap(trap); /* normally done in fall_through */ impossible("dotrap: %ss cannot exist on this level.", defsyms[trap_to_defsym(ttype)].explanation); break; /* don't activate it after all */ @@ -863,27 +880,54 @@ break; } if (webmsgok) { - char verbbuf[BUFSZ]; - verbbuf[0] = '\0'; + char verbbuf[BUFSZ]; + verbbuf[0] = '\0'; #ifdef STEED - if (u.usteed) + if (u.usteed) Sprintf(verbbuf,"lead %s", x_monnam(u.usteed, u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, "poor", SUPPRESS_SADDLE, FALSE)); - else + else #endif Sprintf(verbbuf, "%s", Levitation ? (const char *)"float" : locomotion(youmonst.data, "stumble")); - You("%s into %s spider web!", verbbuf, a_your[trap->madeby_u]); + You("%s into %s spider web!", + verbbuf, a_your[trap->madeby_u]); } u.utraptype = TT_WEB; - /* Time stuck in the web depends on your strength. */ + /* Time stuck in the web depends on your/steed strength. */ { register int str = ACURR(A_STR); +#ifdef STEED + /* If mounted, the steed gets trapped. Use mintrap + * to do all the work. If mtrapped is set as a result, + * unset it and set utrap instead. In the case of a + * strongmonst and mintrap said it's trapped, use a + * short but non-zero trap time. Otherwise, monsters + * have no specific strength, so use player strength. + * This gets skipped for webmsgok, which implies that + * the steed isn't a factor. + */ + if (u.usteed && webmsgok) { + /* mtmp location might not be up to date */ + u.usteed->mx = u.ux; + u.usteed->my = u.uy; + + /* mintrap currently does not return 2(died) for webs */ + if (mintrap(u.usteed)) { + u.usteed->mtrapped = 0; + if (strongmonst(u.usteed->data)) str = 17; + } else { + break; + } + + webmsgok = FALSE; /* mintrap printed the messages */ + } +#endif if (str <= 3) u.utrap = rn1(6,6); else if (str < 6) u.utrap = rn1(6,4); else if (str < 9) u.utrap = rn1(4,4); @@ -894,7 +938,7 @@ else { u.utrap = 0; if (webmsgok) - You("tear through %s web!", a_your[trap->madeby_u]); + You("tear through %s web!", a_your[trap->madeby_u]); deltrap(trap); newsym(u.ux,u.uy); /* get rid of trap symbol */ } @@ -1000,17 +1044,19 @@ fill_pit(u.ux, u.uy); break; - case ROLLING_BOULDER_TRAP: + case ROLLING_BOULDER_TRAP: { + int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0); + seetrap(trap); pline("Click! You trigger a rolling boulder trap!"); if(!launch_obj(BOULDER, trap->launch.x, trap->launch.y, - trap->launch2.x,trap->launch2.y, ROLL)) { + trap->launch2.x, trap->launch2.y, style)) { deltrap(trap); newsym(u.ux,u.uy); /* get rid of trap symbol */ pline("Fortunately for you, no boulder was released."); } break; - + } case MAGIC_PORTAL: seetrap(trap); domagicportal(trap); @@ -1048,7 +1094,7 @@ impossible("steed hit by non-existant arrow?"); return 0; } - if(thitm(8, mtmp, otmp, 0)) trapkilled = TRUE; + if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; steedhit = TRUE; break; case DART_TRAP: @@ -1056,7 +1102,7 @@ impossible("steed hit by non-existant dart?"); return 0; } - if(thitm(7, mtmp, otmp, 0)) trapkilled = TRUE; + if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; steedhit = TRUE; break; case SLP_GAS_TRAP: @@ -1072,7 +1118,7 @@ steedhit = TRUE; break; case LANDMINE: - if (thitm(0, mtmp, (struct obj *)0, rnd(16))) + if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE)) trapkilled = TRUE; steedhit = TRUE; break; @@ -1080,14 +1126,15 @@ case SPIKED_PIT: if (mtmp->mhp <= 0 || thitm(0, mtmp, (struct obj *)0, - rnd((tt == PIT) ? 6 : 10))) + rnd((tt == PIT) ? 6 : 10), FALSE)) trapkilled = TRUE; steedhit = TRUE; break; case POLY_TRAP: if (!resists_magm(mtmp)) { if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { - (void) newcham(mtmp, (struct permonst *)0, FALSE); + (void) newcham(mtmp, (struct permonst *)0, + FALSE, FALSE); if (!can_saddle(mtmp) || !can_ride(mtmp)) { dismount_steed(DISMOUNT_POLY); } else { @@ -1118,7 +1165,7 @@ blow_up_landmine(trap) struct trap *trap; { - scatter(trap->tx, trap->ty, 4, + (void)scatter(trap->tx, trap->ty, 4, MAY_DESTROY | MAY_HIT | MAY_FRACTURE | VIS_EFFECTS, (struct obj *)0); del_engr_at(trap->tx, trap->ty); @@ -1194,6 +1241,11 @@ dx = sgn(x2 - x1); dy = sgn(y2 - y1); switch (style) { + case ROLL|LAUNCH_KNOWN: + /* use otrapped as a flag to ohitmon */ + singleobj->otrapped = 1; + style &= ~LAUNCH_KNOWN; + /* fall through */ case ROLL: delaycnt = 2; /* fall through */ @@ -1223,6 +1275,7 @@ if (rn2(3)) { pline("%s snatches the boulder.", Monnam(mtmp)); + singleobj->otrapped = 0; (void) mpickobj(mtmp, singleobj); used_up = TRUE; break; @@ -1242,7 +1295,7 @@ } if (style == ROLL) { if (down_gate(bhitpos.x, bhitpos.y) != -1) { - if (ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)){ + if(ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)){ used_up = TRUE; break; } @@ -1258,8 +1311,9 @@ deltrap(t); del_engr_at(bhitpos.x,bhitpos.y); place_object(singleobj, bhitpos.x, bhitpos.y); + singleobj->otrapped = 0; fracture_rock(singleobj); - scatter(bhitpos.x,bhitpos.y, 4, + (void)scatter(bhitpos.x,bhitpos.y, 4, MAY_DESTROY|MAY_HIT|MAY_FRACTURE|VIS_EFFECTS, (struct obj *)0); if (cansee(bhitpos.x,bhitpos.y)) @@ -1273,6 +1327,7 @@ pline("Suddenly the rolling boulder disappears!"); else You_hear("a rumbling stop abruptly."); + singleobj->otrapped = 0; if (t->ttyp == TELEP_TRAP) rloco(singleobj); else { @@ -1290,8 +1345,19 @@ seetrap(t); used_up = TRUE; break; + case PIT: + case SPIKED_PIT: + case HOLE: + case TRAPDOOR: + /* the boulder won't be used up if there is a + monster in the trap; stop rolling anyway */ + x2 = bhitpos.x, y2 = bhitpos.y; /* stops here */ + if (flooreffects(singleobj, x2, y2, "fall")) + used_up = TRUE; + dist = -1; /* stop rolling immediately */ + break; } - if (used_up) break; + if (used_up || dist == -1) break; } if (flooreffects(singleobj, bhitpos.x, bhitpos.y, "fall")) { used_up = TRUE; @@ -1299,11 +1365,19 @@ } if (otyp == BOULDER && (otmp2 = sobj_at(BOULDER, bhitpos.x, bhitpos.y)) != 0) { - char *bmsg = - " as one boulder sets another in motion"; - You_hear("a loud crash%s!", + const char *bmsg = + " as one boulder sets another in motion"; + + if (!isok(bhitpos.x + dx, bhitpos.y + dy) || !dist || + IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)) + bmsg = " as one boulder hits another"; + + You_hear("a loud crash%s!", cansee(bhitpos.x, bhitpos.y) ? bmsg : ""); obj_extract_self(otmp2); + /* pass off the otrapped flag to the next boulder */ + otmp2->otrapped = singleobj->otrapped; + singleobj->otrapped = 0; place_object(singleobj, bhitpos.x, bhitpos.y); singleobj = otmp2; otmp2 = (struct obj *)0; @@ -1316,15 +1390,27 @@ levl[bhitpos.x][bhitpos.y].doormask = D_BROKEN; if (dist) unblock_point(bhitpos.x, bhitpos.y); } + + /* if about to hit iron bars, do so now */ + if (dist > 0 && isok(bhitpos.x + dx,bhitpos.y + dy) && + levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) { + x2 = bhitpos.x, y2 = bhitpos.y; /* object stops here */ + if (hits_bars(&singleobj, x2, y2, !rn2(20), 0)) { + if (!singleobj) used_up = TRUE; + break; + } + } } tmp_at(DISP_END, 0); if (!used_up) { + singleobj->otrapped = 0; place_object(singleobj, x2,y2); newsym(x2,y2); return 1; } else return 2; } + #endif /* OVL3 */ #ifdef OVLB @@ -1484,6 +1570,10 @@ In_sokoban(&u.uz) && !trap->madeby_u); const char *fallverb; +#ifdef STEED + /* true when called from dotrap, inescapable is not an option */ + if (mtmp == u.usteed) inescapable = TRUE; +#endif if (!inescapable && ((mtmp->mtrapseen & (1 << (tt-1))) != 0 || (tt == HOLE && !mindless(mtmp->data)))) { @@ -1500,6 +1590,10 @@ /* bug? `in_sight' ought to be split to distinguish between trap_in_sight and can_see_victim to handle invisible monsters */ in_sight = canseemon(mtmp); +#ifdef STEED + /* assume hero can tell what's going on for the steed */ + if (mtmp == u.usteed) in_sight = TRUE; +#endif switch (tt) { case ARROW_TRAP: otmp = mksobj(ARROW, TRUE, FALSE); @@ -1507,7 +1601,7 @@ otmp->owt = weight(otmp); otmp->opoisoned = 0; if (in_sight) seetrap(trap); - if(thitm(8, mtmp, otmp, 0)) trapkilled = TRUE; + if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; break; case DART_TRAP: otmp = mksobj(DART, TRUE, FALSE); @@ -1515,14 +1609,14 @@ otmp->owt = weight(otmp); if (!rn2(6)) otmp->opoisoned = 1; if (in_sight) seetrap(trap); - if(thitm(7, mtmp, otmp, 0)) trapkilled = TRUE; + if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; break; case ROCKTRAP: otmp = mksobj(ROCK, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); if (in_sight) seetrap(trap); - if (thitm(0, mtmp, otmp, d(2, 6))) + if (thitm(0, mtmp, otmp, d(2, 6), FALSE)) trapkilled = TRUE; break; @@ -1655,9 +1749,22 @@ pline("%s is uninjured.", Monnam(mtmp)); } } else { - int num = d(2,4); + int num = d(2,4), alt; + boolean immolate = FALSE; - if (thitm(0, mtmp, (struct obj *)0, num)) + /* paper burns very fast, assume straw is tightly + * packed and burns a bit slower */ + switch (monsndx(mtmp->data)) { + case PM_PAPER_GOLEM: immolate = TRUE; + alt = mtmp->mhpmax; break; + case PM_STRAW_GOLEM: alt = mtmp->mhpmax / 2; break; + case PM_WOOD_GOLEM: alt = mtmp->mhpmax / 4; break; + case PM_LEATHER_GOLEM: alt = mtmp->mhpmax / 8; break; + default: alt = 0; break; + } + if (alt > num) num = alt; + + if (thitm(0, mtmp, (struct obj *)0, num, immolate)) trapkilled = TRUE; else /* we know mhp is at least `num' below mhpmax, @@ -1699,7 +1806,7 @@ mselftouch(mtmp, "Falling, ", FALSE); if (mtmp->mhp <= 0 || thitm(0, mtmp, (struct obj *)0, - rnd((tt == PIT) ? 6 : 10))) + rnd((tt == PIT) ? 6 : 10), FALSE)) trapkilled = TRUE; break; case HOLE: @@ -1843,7 +1950,7 @@ if (!in_sight) pline("Kaablamm! You hear an explosion in the distance!"); blow_up_landmine(trap); - if(thitm(0, mtmp, (struct obj *)0, rnd(16))) + if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE)) trapkilled = TRUE; else { /* monsters recursively fall into new pit */ @@ -1862,7 +1969,8 @@ if (resists_magm(mtmp)) { shieldeff(mtmp->mx, mtmp->my); } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { - (void) newcham(mtmp, (struct permonst *)0, FALSE); + (void) newcham(mtmp, (struct permonst *)0, + FALSE, FALSE); if (in_sight) seetrap(trap); } break; @@ -1920,12 +2028,17 @@ boolean byplayer; { if (resists_ston(mon)) return; - if (cansee(mon->mx, mon->my)) - pline("%s turns to stone.", Monnam(mon)); if (poly_when_stoned(mon->data)) { mon_to_stone(mon); return; } + + /* give a " is slowing down" message and also remove + intrinsic speed (comparable to similar effect on the hero) */ + mon_adjust_speed(mon, -3, (struct obj *)0); + + if (cansee(mon->mx, mon->my)) + pline("%s turns to stone.", Monnam(mon)); if (byplayer) { stoned = TRUE; xkilled(mon,0); @@ -2047,6 +2160,11 @@ HLevitation &= ~hmask; ELevitation &= ~emask; if(Levitation) return(0); /* maybe another ring/potion/boots */ + if(u.uswallow) { + You("float down, but you are still %s.", + is_animal(u.ustuck->data) ? "swallowed" : "engulfed"); + return(1); + } if (Punished && !carried(uball) && (is_pool(uball->ox, uball->oy) || @@ -2152,7 +2270,7 @@ struct obj *box; /* null for floor trap */ { boolean see_it = !Blind; - int num; + int num, alt; /* Bug: for box case, the equivalent of burn_floor_paper() ought * to be done upon its contents. @@ -2171,6 +2289,18 @@ if (Fire_resistance) { shieldeff(u.ux, u.uy); num = rn2(2); + } else if (Upolyd) { + num = d(2,4); + switch (u.umonnum) { + case PM_PAPER_GOLEM: alt = u.mhmax; break; + case PM_STRAW_GOLEM: alt = u.mhmax / 2; break; + case PM_WOOD_GOLEM: alt = u.mhmax / 4; break; + case PM_LEATHER_GOLEM: alt = u.mhmax / 8; break; + default: alt = 0; break; + } + if (alt > num) num = alt; + if (u.mhmax > mons[u.umonnum].mlevel) + u.mhmax -= rn2(min(u.mhmax,num + 1)), flags.botl = 1; } else { num = d(2,4); if (u.uhpmax > u.ulevel) @@ -2392,9 +2522,12 @@ register struct obj *obj; register boolean force, here; { + struct obj *otmp; + /* Scrolls, spellbooks, potions, weapons and pieces of armor may get affected by the water */ - for (; obj; obj = (here ? obj->nexthere : obj->nobj)) { + for (; obj; obj = otmp) { + otmp = here ? obj->nexthere : obj->nobj; (void) snuff_lit(obj); @@ -2426,7 +2559,12 @@ pline("Steam rises from %s.", the(xname(obj))); else obj->otyp = SPE_BLANK_PAPER; } else if (obj->oclass == POTION_CLASS) { - if (obj->odiluted) { + if (obj->otyp == POT_ACID) { + /* damage player/monster? */ + pline("A potion explodes!"); + delobj(obj); + continue; + } else if (obj->odiluted) { obj->otyp = POT_WATER; obj->blessed = obj->cursed = 0; obj->odiluted = 0; @@ -2456,64 +2594,64 @@ { int invc = inv_cnt(); - while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) { - register struct obj *obj, *otmp = (struct obj *)0; - register int i; + register struct obj *obj, *otmp = (struct obj *)0; + register int i; - /* Pick a random object */ - if (invc > 0) { - i = rn2(invc); + /* Pick a random object */ + if (invc > 0) { + i = rn2(invc); for (obj = invent; obj; obj = obj->nobj) { - /* - * Undroppables are: body armor, boots, gloves, - * amulets, and rings because of the time and effort - * in removing them + loadstone and other cursed stuff - * for obvious reasons. - */ - if (!((obj->otyp == LOADSTONE && obj->cursed) || - obj == uamul || obj == uleft || obj == uright || - obj == ublindf || obj == uarm || obj == uarmc || - obj == uarmg || obj == uarmf || + /* + * Undroppables are: body armor, boots, gloves, + * amulets, and rings because of the time and effort + * in removing them + loadstone and other cursed stuff + * for obvious reasons. + */ + if (!((obj->otyp == LOADSTONE && obj->cursed) || + obj == uamul || obj == uleft || obj == uright || + obj == ublindf || obj == uarm || obj == uarmc || + obj == uarmg || obj == uarmf || #ifdef TOURIST - obj == uarmu || + obj == uarmu || #endif - (obj->cursed && (obj == uarmh || obj == uarms)) || - welded(obj))) - otmp = obj; - /* reached the mark and found some stuff to drop? */ - if (--i < 0 && otmp) break; + (obj->cursed && (obj == uarmh || obj == uarms)) || + welded(obj))) + otmp = obj; + /* reached the mark and found some stuff to drop? */ + if (--i < 0 && otmp) break; - /* else continue */ - } + /* else continue */ } + } #ifndef GOLDOBJ - if (!otmp) { - /* Nothing available left to drop; try gold */ - if (u.ugold) { - pline("In desperation, you drop your purse."); - /* Hack: gold is not in the inventory, so make a gold object - * and put it at the head of the inventory list. - */ - obj = mkgoldobj(u.ugold); /* removes from u.ugold */ - u.ugold = obj->quan; /* put the gold back */ - assigninvlet(obj); /* might end up as NOINVSYM */ - obj->nobj = invent; - invent = obj; - *lostsome = TRUE; - dropx(obj); - continue; /* Try again */ - } - /* We can't even drop gold! */ - return (FALSE); + if (!otmp) { + /* Nothing available left to drop; try gold */ + if (u.ugold) { + pline("In desperation, you drop your purse."); + /* Hack: gold is not in the inventory, so make a gold object + * and put it at the head of the inventory list. + */ + obj = mkgoldobj(u.ugold); /* removes from u.ugold */ + obj->in_use = TRUE; + u.ugold = obj->quan; /* put the gold back */ + assigninvlet(obj); /* might end up as NOINVSYM */ + obj->nobj = invent; + invent = obj; + *lostsome = TRUE; + dropx(obj); + continue; /* Try again */ } + /* We can't even drop gold! */ + return (FALSE); + } #else - if (!otmp) return (FALSE); /* nothing to drop! */ + if (!otmp) return (FALSE); /* nothing to drop! */ #endif - if (otmp->owornmask && otmp != uball) remove_worn_item(otmp); - *lostsome = TRUE; - dropx(otmp); - invc--; + if (otmp->owornmask) remove_worn_item(otmp, FALSE); + *lostsome = TRUE; + dropx(otmp); + invc--; } return(TRUE); } @@ -2584,8 +2722,8 @@ vision_full_recalc = 1; return(FALSE); } - if((Teleportation || can_teleport(youmonst.data)) && - (Teleport_control || rn2(3) < Luck+2)) { + if ((Teleportation || can_teleport(youmonst.data)) && + !u.usleep && (Teleport_control || rn2(3) < Luck+2)) { You("attempt a teleport spell."); /* utcsri!carroll */ (void) dotele(); if(!is_pool(u.ux,u.uy)) @@ -2599,11 +2737,17 @@ } #endif crawl_ok = FALSE; + /* if sleeping, wake up now so that we don't crawl out of water + while still asleep; we can't do that the same way that waking + due to combat is handled; note unmul() clears u.usleep */ + if (u.usleep) unmul("Suddenly you wake up!"); + /* can't crawl if unable to move (crawl_ok flag stays false) */ + if (multi < 0 || (Upolyd && !youmonst.data->mmove)) goto crawl; /* look around for a place to crawl to */ for (i = 0; i < 100; i++) { x = rn1(3,u.ux - 1); y = rn1(3,u.uy - 1); - if (goodpos(x, y, &youmonst)) { + if (goodpos(x, y, &youmonst, 0)) { crawl_ok = TRUE; goto crawl; } @@ -2611,11 +2755,11 @@ /* one more scan */ for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) - if (goodpos(x, y, &youmonst)) { + if (goodpos(x, y, &youmonst, 0)) { crawl_ok = TRUE; goto crawl; } -crawl:; + crawl: if (crawl_ok) { boolean lost = FALSE; /* time to do some strip-tease... */ @@ -2627,7 +2771,7 @@ You("dump some of your gear to lose weight..."); if (succ) { pline("Pheew! That was close."); - teleds(x,y); + teleds(x,y,TRUE); return(TRUE); } /* still too much weight */ @@ -2640,13 +2784,15 @@ "pool of water" : "moat"; done(DROWNING); /* oops, we're still alive. better get out of the water. */ - while (!safe_teleds()) { + while (!safe_teleds(TRUE)) { pline("You're still drowning."); done(DROWNING); } - u.uinwater = 0; - You("find yourself back %s.", Is_waterlevel(&u.uz) ? + if (u.uinwater) { + u.uinwater = 0; + You("find yourself back %s.", Is_waterlevel(&u.uz) ? "in an air bubble" : "on land"); + } return(TRUE); } @@ -2743,7 +2889,8 @@ boolean unused; /* we know there's no monster in the way, and we're not trapped */ - if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused)) { + if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused, + TRUE)) { u.ux0 = u.ux, u.uy0 = u.uy; u.ux = x, u.uy = y; u.umoved = TRUE; @@ -2751,7 +2898,7 @@ vision_recalc(1); check_leash(u.ux0, u.uy0); if (Punished) move_bc(0, bc, bx, by, cx, cy); - spoteffects(TRUE); /* dotrap() */ + spoteffects(FALSE); /* dotrap() */ exercise(A_WIS, FALSE); } } @@ -2820,6 +2967,12 @@ if (ttmp2) { pline_The("webbing sticks to you. You're caught too!"); dotrap(ttmp2, NOWEBMSG); +#ifdef STEED + if (u.usteed && u.utrap) { + /* you, not steed, are trapped */ + dismount_steed(DISMOUNT_FELL); + } +#endif } } else pline("%s remains entangled.", Monnam(mtmp)); @@ -2847,6 +3000,7 @@ { if (!ttmp->madeby_u) { if (rnl(10) < 8 && !mtmp->mpeaceful && + !mtmp->msleeping && !mtmp->mfrozen && !mindless(mtmp->data) && mtmp->data->mlet != S_HUMAN) { mtmp->mpeaceful = 1; @@ -3086,17 +3240,54 @@ struct trap *ttmp; struct monst *mtmp; boolean trap_skipped = FALSE; + boolean box_here = FALSE; + boolean deal_with_floor_trap = FALSE; + char the_trap[BUFSZ], qbuf[QBUFSZ]; + int containercnt = 0; if(!getdir((char *)0)) return(0); x = u.ux + u.dx; y = u.uy + u.dy; + for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) { + if(Is_box(otmp) && !u.dx && !u.dy) { + box_here = TRUE; + containercnt++; + if (containercnt > 1) break; + } + } + if ((ttmp = t_at(x,y)) && ttmp->tseen) { - if (u.utrap) { - You("cannot deal with traps while trapped!"); - return 1; + deal_with_floor_trap = TRUE; + Strcpy(the_trap, the(defsyms[trap_to_defsym(ttmp->ttyp)].explanation)); + if (box_here) { + if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) { + You_cant("do much about %s%s.", + the_trap, u.utrap ? + " that you're stuck in" : + " while standing on the edge of it"); + trap_skipped = TRUE; + deal_with_floor_trap = FALSE; + } else { + Sprintf(qbuf, "There %s and %s here. %s %s?", + (containercnt == 1) ? "is a container" : "are containers", + an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation), + ttmp->ttyp == WEB ? "Remove" : "Disarm", the_trap); + switch (ynq(qbuf)) { + case 'q': return(0); + case 'n': trap_skipped = TRUE; + deal_with_floor_trap = FALSE; + break; + } + } } - switch(ttmp->ttyp) { + if (deal_with_floor_trap) { + if (u.utrap) { + You("cannot deal with %s while trapped%s!", the_trap, + (x == u.ux && y == u.uy) ? " in it" : ""); + return 1; + } + switch(ttmp->ttyp) { case BEAR_TRAP: case WEB: return disarm_holdingtrap(ttmp); @@ -3122,15 +3313,15 @@ default: You("cannot disable %s trap.", (u.dx || u.dy) ? "that" : "this"); return 0; - } /* end switch */ + } + } } /* end if */ if(!u.dx && !u.dy) { for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if(Is_box(otmp)) { - There("is %s here.", doname(otmp)); - - switch (ynq("Check for traps?")) { + Sprintf(qbuf, "There is %s here. Check it for traps?", doname(otmp)); + switch (ynq(qbuf)) { case 'q': return(0); case 'n': continue; } @@ -3298,6 +3489,18 @@ loss += stolen_value(obj, ox, oy, (boolean)shkp->mpeaceful, TRUE); delete_contents(obj); + /* we're about to delete all things at this location, + * which could include the ball & chain. + * If we attempt to call unpunish() in the + * for-loop below we can end up with otmp2 + * being invalid once the chain is gone. + * Deal with ball & chain right now instead. + */ + if (Punished && !carried(uball) && + ((uchain->ox == u.ux && uchain->oy == u.uy) || + (uball->ox == u.ux && uball->oy == u.uy))) + unpunish(); + for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; @@ -3376,8 +3579,8 @@ case 1: case 0: pline("A cloud of %s gas billows from %s.", - hcolor((char *)0), - the(xname(obj))); + Blind ? blindgas[rn2(SIZE(blindgas))] : + hcolor((char *)0), the(xname(obj))); if(!Stunned) { if (Hallucination) pline("What a groovy feeling!"); @@ -3433,7 +3636,8 @@ dealloc_trap(trap); } -boolean delfloortrap(ttmp) +boolean +delfloortrap(ttmp) register struct trap *ttmp; { /* Destroy a trap that emanates from the floor. */ @@ -3485,14 +3689,15 @@ /* Monster is hit by trap. */ /* Note: doesn't work if both obj and d_override are null */ STATIC_OVL boolean -thitm(tlev, mon, obj, d_override) -register int tlev; -register struct monst *mon; -register struct obj *obj; +thitm(tlev, mon, obj, d_override, nocorpse) +int tlev; +struct monst *mon; +struct obj *obj; int d_override; +boolean nocorpse; { - register int strike; - register boolean trapkilled = FALSE; + int strike; + boolean trapkilled = FALSE; if (d_override) strike = 1; else if (obj) strike = (find_mac(mon) + tlev + obj->spe <= rnd(20)); @@ -3518,7 +3723,7 @@ int xx = mon->mx; int yy = mon->my; - monkilled(mon, "", AD_PHYS); + monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS); if (mon->mhp <= 0) { newsym(xx, yy); trapkilled = TRUE; @@ -3542,7 +3747,7 @@ !strncmp(nomovemsg,"You are consci", 14)))); } -static char lava_killer[] = "molten lava"; +static const char lava_killer[] = "molten lava"; boolean lava_effects() @@ -3603,7 +3808,7 @@ killer = lava_killer; You("burn to a crisp..."); done(BURNING); - while (!safe_teleds()) { + while (!safe_teleds(TRUE)) { pline("You're still burning."); done(BURNING); } diff -Naurd ../nethack-3.4.0/src/u_init.c ./src/u_init.c --- ../nethack-3.4.0/src/u_init.c Wed Mar 20 23:43:20 2002 +++ ./src/u_init.c Mon Feb 24 15:25:05 2003 @@ -215,7 +215,7 @@ }; #ifdef GOLDOBJ static struct trobj Money[] = { - { GOLD_PIECE, 0 , GOLD_CLASS, 1, 0 }, + { GOLD_PIECE, 0 , COIN_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; #endif @@ -251,7 +251,7 @@ { NON_PM, STRANGE_OBJECT, STRANGE_OBJECT } }; -static struct def_skill Skill_A[] = { +static const struct def_skill Skill_A[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_BASIC }, { P_PICK_AXE, P_EXPERT }, { P_SHORT_SWORD, P_BASIC }, { P_SCIMITAR, P_SKILLED }, { P_SABER, P_EXPERT }, @@ -269,7 +269,7 @@ { P_NONE, 0 } }; -static struct def_skill Skill_B[] = { +static const struct def_skill Skill_B[] = { { P_DAGGER, P_BASIC }, { P_AXE, P_EXPERT }, { P_PICK_AXE, P_EXPERT }, { P_SHORT_SWORD, P_BASIC }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_SKILLED }, @@ -288,7 +288,7 @@ { P_NONE, 0 } }; -static struct def_skill Skill_C[] = { +static const struct def_skill Skill_C[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_SKILLED }, { P_AXE, P_SKILLED }, { P_PICK_AXE, P_BASIC }, { P_CLUB, P_EXPERT }, { P_MACE, P_EXPERT }, @@ -303,7 +303,7 @@ { P_NONE, 0 } }; -static struct def_skill Skill_H[] = { +static const struct def_skill Skill_H[] = { { P_DAGGER, P_SKILLED }, { P_KNIFE, P_EXPERT }, { P_SHORT_SWORD, P_SKILLED }, { P_SCIMITAR, P_BASIC }, { P_SABER, P_BASIC }, { P_CLUB, P_SKILLED }, @@ -317,7 +317,7 @@ { P_NONE, 0 } }; -static struct def_skill Skill_K[] = { +static const struct def_skill Skill_K[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_BASIC }, { P_AXE, P_SKILLED }, { P_PICK_AXE, P_BASIC }, { P_SHORT_SWORD, P_SKILLED }, { P_BROAD_SWORD, P_SKILLED }, @@ -339,7 +339,7 @@ { P_NONE, 0 } }; -static struct def_skill Skill_Mon[] = { +static const struct def_skill Skill_Mon[] = { { P_QUARTERSTAFF, P_BASIC }, { P_SPEAR, P_BASIC }, { P_JAVELIN, P_BASIC }, { P_CROSSBOW, P_BASIC }, { P_SHURIKEN, P_BASIC }, @@ -351,7 +351,7 @@ { P_NONE, 0 } }; -static struct def_skill Skill_P[] = { +static const struct def_skill Skill_P[] = { { P_CLUB, P_EXPERT }, { P_MACE, P_EXPERT }, { P_MORNING_STAR, P_EXPERT }, { P_FLAIL, P_EXPERT }, { P_HAMMER, P_EXPERT }, { P_QUARTERSTAFF, P_EXPERT }, @@ -367,7 +367,7 @@ { P_NONE, 0 } }; -static struct def_skill Skill_R[] = { +static const struct def_skill Skill_R[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_EXPERT }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_SKILLED }, { P_TWO_HANDED_SWORD, P_BASIC }, @@ -387,7 +387,7 @@ { P_NONE, 0 } }; -static struct def_skill Skill_Ran[] = { +static const struct def_skill Skill_Ran[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_SKILLED }, { P_AXE, P_SKILLED }, { P_PICK_AXE, P_BASIC }, { P_SHORT_SWORD, P_BASIC }, { P_MORNING_STAR, P_BASIC }, @@ -408,7 +408,7 @@ { P_NONE, 0 } }; -static struct def_skill Skill_S[] = { +static const struct def_skill Skill_S[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_SKILLED }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_EXPERT }, { P_TWO_HANDED_SWORD, P_EXPERT }, @@ -427,7 +427,7 @@ }; #ifdef TOURIST -static struct def_skill Skill_T[] = { +static const struct def_skill Skill_T[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_SKILLED }, { P_AXE, P_BASIC }, { P_PICK_AXE, P_BASIC }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_BASIC }, @@ -453,7 +453,7 @@ }; #endif /* TOURIST */ -static struct def_skill Skill_V[] = { +static const struct def_skill Skill_V[] = { { P_DAGGER, P_EXPERT }, { P_AXE, P_EXPERT }, { P_PICK_AXE, P_SKILLED }, { P_SHORT_SWORD, P_SKILLED }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_EXPERT }, @@ -472,7 +472,7 @@ { P_NONE, 0 } }; -static struct def_skill Skill_W[] = { +static const struct def_skill Skill_W[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_SKILLED }, { P_AXE, P_SKILLED }, { P_SHORT_SWORD, P_BASIC }, { P_CLUB, P_SKILLED }, { P_MACE, P_BASIC }, @@ -850,7 +850,7 @@ restricted_spell_discipline(otyp) int otyp; { - struct def_skill *skills; + const struct def_skill *skills; int this_skill = spell_skilltype(otyp); switch (Role_switch) { @@ -980,7 +980,7 @@ } #ifdef GOLDOBJ - if (trop->trclass == GOLD_CLASS) { + if (trop->trclass == COIN_CLASS) { /* no "blessed" or "identified" money */ obj->quan = u.umoney0; } else { diff -Naurd ../nethack-3.4.0/src/uhitm.c ./src/uhitm.c --- ../nethack-3.4.0/src/uhitm.c Wed Mar 20 23:43:20 2002 +++ ./src/uhitm.c Mon Feb 24 15:25:05 2003 @@ -8,6 +8,10 @@ STATIC_DCL void FDECL(steal_it, (struct monst *, struct attack *)); STATIC_DCL boolean FDECL(hitum, (struct monst *,int,struct attack *)); STATIC_DCL boolean FDECL(hmon_hitmon, (struct monst *,struct obj *,int)); +#ifdef STEED +STATIC_DCL int FDECL(joust, (struct monst *,struct obj *)); +#endif +STATIC_DCL void NDECL(demonpet); STATIC_DCL boolean FDECL(m_slips_free, (struct monst *mtmp,struct attack *mattk)); STATIC_DCL int FDECL(explum, (struct monst *,struct attack *)); STATIC_DCL void FDECL(start_engulf, (struct monst *)); @@ -15,6 +19,7 @@ STATIC_DCL int FDECL(gulpum, (struct monst *,struct attack *)); STATIC_DCL boolean FDECL(hmonas, (struct monst *,int)); STATIC_DCL void FDECL(nohandglow, (struct monst *)); +STATIC_DCL boolean FDECL(shade_aware, (struct obj *)); extern boolean notonhead; /* for long worms */ /* The below might become a parameter instead if we use it a lot */ @@ -205,6 +210,22 @@ return(FALSE); } +/* + * It is unchivalrous for a knight to attack the defenseless or from behind. + */ +void +check_caitiff(mtmp) +struct monst *mtmp; +{ + if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL && + (!mtmp->mcanmove || mtmp->msleeping || + (mtmp->mflee && !mtmp->mavenge)) && + u.ualign.record > -10) { + You("caitiff!"); + adjalign(-1); + } +} + schar find_roll_to_hit(mtmp) register struct monst *mtmp; @@ -215,14 +236,7 @@ tmp = 1 + Luck + abon() + find_mac(mtmp) + u.uhitinc + maybe_polyd(youmonst.data->mlevel, u.ulevel); -/* it is unchivalrous to attack the defenseless or from behind */ - if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL && - (!mtmp->mcanmove || mtmp->msleeping || - (mtmp->mflee && !mtmp->mavenge)) && - u.ualign.record > -10) { - You("caitiff!"); - adjalign(-1); - } + check_caitiff(mtmp); /* attacking peaceful creatures is bad for the samurai's giri */ if (Role_if(PM_SAMURAI) && mtmp->mpeaceful && @@ -254,8 +268,9 @@ if (uarm) { Your("armor is rather cumbersome..."); tmp -= urole.spelarmr; - } else if (!uwep) + } else if (!uwep && !uarms) { tmp += (u.ulevel / 3) + 2; + } } /* with a lot of luggage, your agility diminishes */ @@ -410,17 +425,20 @@ if(!*mhit) { missum(mon, uattk); } else { - int oldhp = mon->mhp; + int oldhp = mon->mhp, + x = u.ux + u.dx, y = u.uy + u.dy; - /* KMH, conduct */ - if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) - u.uconduct.weaphit++; + /* KMH, conduct */ + if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) + u.uconduct.weaphit++; - /* we hit the monster; be careful: it might die! */ - notonhead = (mon->mx != u.ux+u.dx || mon->my != u.uy+u.dy); + /* we hit the monster; be careful: it might die or + be knocked into a different location */ + notonhead = (mon->mx != x || mon->my != y); malive = hmon(mon, uwep, 0); - /* This assumes that Stormbringer was uwep not uswapwep */ - if (malive && u.twoweap && !override_confirmation) + /* this assumes that Stormbringer was uwep not uswapwep */ + if (malive && u.twoweap && !override_confirmation && + m_at(x, y) == mon) malive = hmon(mon, uswapwep, 0); if (malive) { /* monster still alive */ @@ -444,7 +462,7 @@ --u.uconduct.weaphit; } if (mon->wormno && *mhit) - cutworm(mon, u.ux+u.dx, u.uy+u.dy, uwep); + cutworm(mon, x, y, uwep); } } return(malive); @@ -499,18 +517,21 @@ * associated with the damage don't come out until _after_ outputting * a hit message. */ - boolean hittxt = FALSE, destroyed = FALSE; + boolean hittxt = FALSE, destroyed = FALSE, already_killed = FALSE; boolean get_dmg_bonus = TRUE; boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE; boolean silvermsg = FALSE; + boolean valid_weapon_attack = FALSE; + boolean unarmed = !uwep && !uarm && !uarms; #ifdef STEED - boolean jousting = FALSE; + int jousting = 0; #endif - boolean valid_weapon_attack = FALSE; int wtype; struct obj *monwep; char yourbuf[BUFSZ]; + char unconventional[BUFSZ]; /* substituted for word "attack" in msg */ + unconventional[0] = '\0'; wakeup(mon); if(!obj) { /* attack with bare hands */ if (mdat == &mons[PM_SHADE]) @@ -558,6 +579,20 @@ tmp = 0; else tmp = rnd(2); + if (!thrown && obj == uwep && obj->otyp == BOOMERANG && + rnl(4) == 4-1) { + boolean more_than_1 = (obj->quan > 1L); + + pline("As you hit %s, %s%s %s breaks into splinters.", + mon_nam(mon), more_than_1 ? "one of " : "", + shk_your(yourbuf, obj), xname(obj)); + if (!more_than_1) uwepgone(); /* set unweapon */ + useup(obj); + if (!more_than_1) obj = (struct obj *) 0; + hittxt = TRUE; + if (mdat != &mons[PM_SHADE]) + tmp++; + } } else { tmp = dmgval(obj, mon); /* a minimal hit doesn't exercise proficiency */ @@ -610,20 +645,14 @@ && hates_silver(mdat)) silvermsg = TRUE; #ifdef STEED - if (u.usteed && !thrown && - weapon_type(obj) == P_LANCE && mon != u.ustuck) - jousting = TRUE; + if (u.usteed && !thrown && tmp > 0 && + weapon_type(obj) == P_LANCE && mon != u.ustuck) { + jousting = joust(mon, obj); + /* exercise skill even for minimal damage hits */ + if (jousting) valid_weapon_attack = TRUE; + } #endif - if(!thrown && obj == uwep && obj->otyp == BOOMERANG && - !rnl(3)) { - pline("As you hit %s, %s breaks into splinters.", - mon_nam(mon), the(xname(obj))); - useup(obj); - obj = (struct obj *) 0; - hittxt = TRUE; - if (mdat != &mons[PM_SHADE]) - tmp++; - } else if(thrown && (is_ammo(obj) || is_missile(obj))) { + if (thrown && (is_ammo(obj) || is_missile(obj))) { if (ammo_and_launcher(obj, uwep)) { /* Elves and Samurai do extra damage using * their bows&arrows; they're highly trained. @@ -653,14 +682,15 @@ mdat = mon->data; tmp = (mdat == &mons[PM_SHADE]) ? 0 : 1; } else { - boolean shade_aware = FALSE; - - switch(obj->otyp) { + if (mdat == &mons[PM_SHADE] && !shade_aware(obj)) { + tmp = 0; + Strcpy(unconventional, cxname(obj)); + } else { + switch(obj->otyp) { case BOULDER: /* 1d20 */ case HEAVY_IRON_BALL: /* 1d25 */ case IRON_CHAIN: /* 1d4+1 */ tmp = dmgval(obj, mon); - shade_aware = TRUE; /* dmgval handles it */ break; case MIRROR: if (breaktest(obj)) { @@ -669,6 +699,8 @@ change_luck(-2); useup(obj); obj = (struct obj *) 0; + unarmed = FALSE; /* avoid obj==0 confusion */ + get_dmg_bonus = FALSE; hittxt = TRUE; } tmp = 1; @@ -676,9 +708,11 @@ #ifdef TOURIST case EXPENSIVE_CAMERA: You("succeed in destroying %s camera. Congratulations!", - shk_your(yourbuf, obj)); + shk_your(yourbuf, obj)); useup(obj); return(TRUE); + /*NOTREACHED*/ + break; #endif case CORPSE: /* fixed by polder@cs.vu.nl */ if (touch_petrifies(&mons[obj->corpsenm])) { @@ -722,7 +756,7 @@ if (touch_petrifies(&mons[obj->corpsenm])) { /*learn_egg_type(obj->corpsenm);*/ - You("hit %s with %s %s egg%s. Splat!", + pline("Splat! You hit %s with %s %s egg%s!", mon_nam(mon), obj->known ? "the" : cnt > 1L ? "some" : "a", obj->known ? mons[obj->corpsenm].mname : "petrifying", @@ -825,11 +859,8 @@ if(tmp < 1) tmp = 1; else tmp = rnd(tmp); if(tmp > 6) tmp = 6; + } } - - if (!shade_aware && mdat == &mons[PM_SHADE] && obj && - objects[obj->otyp].oc_material != SILVER) - tmp = 0; } } @@ -883,7 +914,9 @@ tmp = 0; if (mdat == &mons[PM_SHADE]) { if (!hittxt) { - Your("attack passes harmlessly through %s.", + const char *what = unconventional[0] ? unconventional : "attack"; + Your("%s %s harmlessly through %s.", + what, vtense(what, "pass"), mon_nam(mon)); hittxt = TRUE; } @@ -894,27 +927,48 @@ #ifdef STEED if (jousting) { + tmp += d(2, (obj == uwep) ? 10 : 2); /* [was in dmgval()] */ You("joust %s%s", mon_nam(mon), canseemon(mon) ? exclam(tmp) : "."); - mhurtle(mon, u.dx, u.dy, 1); + if (jousting < 0) { + Your("%s shatters on impact!", xname(obj)); + /* (must be either primary or secondary weapon to get here) */ + u.twoweap = FALSE; /* untwoweapon() is too verbose here */ + if (obj == uwep) uwepgone(); /* set unweapon */ + /* minor side-effect: broken lance won't split puddings */ + useup(obj); + obj = 0; + } + /* avoid migrating a dead monster */ + if (mon->mhp > tmp) { + mhurtle(mon, u.dx, u.dy, 1); + if (DEADMONSTER(mon)) already_killed = TRUE; + } hittxt = TRUE; } else #endif /* VERY small chance of stunning opponent if unarmed. */ - if (tmp > 1 && !thrown && !obj && !uwep && !uarm && !uarms && !Upolyd) { + if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) { if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) && !bigmonst(mdat) && !thick_skinned(mdat)) { if (canspotmon(mon)) pline("%s %s from your powerful strike!", Monnam(mon), makeplural(stagger(mon->data, "stagger"))); - mhurtle(mon, u.dx, u.dy, 1); + /* avoid migrating a dead monster */ + if (mon->mhp > tmp) { + mhurtle(mon, u.dx, u.dy, 1); + if (DEADMONSTER(mon)) already_killed = TRUE; + } hittxt = TRUE; } } - mon->mhp -= tmp; - if(mon->mhp < 1) + if (!already_killed) mon->mhp -= tmp; + /* adjustments might have made tmp become less than what + a level draining artifact has already done to max HP */ + if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; + if (mon->mhp < 1) destroyed = TRUE; if (mon->mtame && (!mon->mflee || mon->mfleetim) && tmp > 0) { abuse_dog(mon); @@ -964,13 +1018,14 @@ pline_The("poison doesn't seem to affect %s.", mon_nam(mon)); if (poiskilled) { pline_The("poison was deadly..."); - xkilled(mon, 0); + if (!already_killed) xkilled(mon, 0); return FALSE; } else if (destroyed) { - killed(mon); /* takes care of most messages */ + if (!already_killed) + killed(mon); /* takes care of most messages */ } else if(u.umconf && !thrown) { nohandglow(mon); - if(!mon->mconf && !resist(mon, '+', 0, NOTELL)) { + if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) { mon->mconf = 1; if (!mon->mstun && mon->mcanmove && !mon->msleeping && canseemon(mon)) @@ -981,6 +1036,27 @@ return((boolean)(destroyed ? FALSE : TRUE)); } +STATIC_OVL boolean +shade_aware(obj) +struct obj *obj; +{ + if (!obj) return FALSE; + /* + * The things in this list either + * 1) affect shades. + * OR + * 2) are dealt with properly by other routines + * when it comes to shades. + */ + if (obj->otyp == BOULDER || obj->otyp == HEAVY_IRON_BALL + || obj->otyp == IRON_CHAIN /* dmgval handles those first three */ + || obj->otyp == MIRROR /* silver in the reflective surface */ + || obj->otyp == CLOVE_OF_GARLIC /* causes shades to flee */ + || objects[obj->otyp].oc_material == SILVER) + return TRUE; + return FALSE; +} + /* check whether slippery clothing protects from hug or wrap attack */ /* [currently assumes that you are the attacker] */ STATIC_OVL boolean @@ -1025,7 +1101,34 @@ return FALSE; } -STATIC_DCL void NDECL(demonpet); +/* used when hitting a monster with a lance while mounted */ +STATIC_OVL int /* 1: joust hit; 0: ordinary hit; -1: joust but break lance */ +joust(mon, obj) +struct monst *mon; /* target */ +struct obj *obj; /* weapon */ +{ + int skill_rating, joust_dieroll; + + if (Fumbling || Stunned) return 0; + /* sanity check; lance must be wielded in order to joust */ + if (obj != uwep && (obj != uswapwep || !u.twoweap)) return 0; + + /* if using two weapons, use worse of lance and two-weapon skills */ + skill_rating = P_SKILL(weapon_type(obj)); /* lance skill */ + if (u.twoweap && P_SKILL(P_TWO_WEAPON_COMBAT) < skill_rating) + skill_rating = P_SKILL(P_TWO_WEAPON_COMBAT); + if (skill_rating == P_ISRESTRICTED) skill_rating = P_UNSKILLED; /* 0=>1 */ + + /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */ + if ((joust_dieroll = rn2(5)) < skill_rating) { + if (joust_dieroll == 0 && rnl(50) == (50-1) && + !unsolid(mon->data) && !obj_resists(obj, 0, 100)) + return -1; /* hit that breaks lance */ + return 1; /* successful joust */ + } + return 0; /* no joust bonus; revert to ordinary attack */ +} + /* * Send in a demon pet for the hero. Exercise wisdom. * @@ -1098,22 +1201,26 @@ } while ((otmp = mdef->minvent) != 0) { + if (!Upolyd) break; /* no longer have ability to steal */ /* take the object away from the monster */ obj_extract_self(otmp); if ((unwornmask = otmp->owornmask) != 0L) { mdef->misc_worn_check &= ~unwornmask; - if (otmp->owornmask & W_WEP) + if (otmp->owornmask & W_WEP) { setmnotwielded(mdef,otmp); + MON_NOWEP(mdef); + } otmp->owornmask = 0L; - update_mon_intrinsics(mdef, otmp, FALSE); + update_mon_intrinsics(mdef, otmp, FALSE, FALSE); if (otmp == stealoid) /* special message for final item */ pline("%s finishes taking off %s suit.", Monnam(mdef), mhis(mdef)); } /* give the object to the character */ - otmp = hold_another_object(otmp, "You steal %s.", + otmp = hold_another_object(otmp, "You snatched but dropped %s.", doname(otmp), "You steal: "); + if (otmp->where != OBJ_INVENT) continue; if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !uarmg) { char kbuf[BUFSZ]; @@ -1124,7 +1231,7 @@ } /* more take-away handling, after theft message */ if (unwornmask & W_WEP) { /* stole wielded weapon */ - possibly_unwield(mdef); + possibly_unwield(mdef, FALSE); } else if (unwornmask & W_ARMG) { /* stole worn gloves */ mselftouch(mdef, (const char *)0, TRUE); if (mdef->mhp <= 0) /* it's now a statue */ @@ -1142,6 +1249,12 @@ { register struct permonst *pd = mdef->data; register int tmp = d((int)mattk->damn, (int)mattk->damd); + int armpro; + boolean negated; + + armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + negated = !((rn2(3) >= armpro) || !rn2(50)); if (is_demon(youmonst.data) && !rn2(13) && !uwep && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS @@ -1155,11 +1268,17 @@ pline("%s %s for a moment.", Monnam(mdef), makeplural(stagger(mdef->data, "stagger"))); mdef->mstun = 1; - /* fall through to next case */ - case AD_WERE: /* no effect on monsters */ - case AD_HEAL: + goto physical; case AD_LEGS: + /* if (u.ucancelled) { */ + /* tmp = 0; */ + /* break; */ + /* } */ + goto physical; + case AD_WERE: /* no special effect on monsters */ + case AD_HEAL: /* likewise */ case AD_PHYS: + physical: if(mattk->aatyp == AT_WEAP) { if(uwep) tmp = 0; } else if(mattk->aatyp == AT_KICK) { @@ -1174,16 +1293,21 @@ } break; case AD_FIRE: + if (negated) { + tmp = 0; + break; + } if (!Blind) pline("%s is %s!", Monnam(mdef), - mdef->data == &mons[PM_WATER_ELEMENTAL] ? "boiling" : - mattk->aatyp == AT_HUGS ? - "being roasted" : "on fire"); + on_fire(mdef->data, mattk)); if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) { if (!Blind) - pline("%s burns completely!", Monnam(mdef)); - xkilled(mdef,0); + pline("%s burns completely!", Monnam(mdef)); + xkilled(mdef,2); + tmp = 0; + break; + /* Don't return yet; keep hp<1 and tmp=0 for pet msg */ } tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); @@ -1198,6 +1322,10 @@ tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE); break; case AD_COLD: + if (negated) { + tmp = 0; + break; + } if (!Blind) pline("%s is covered in frost!", Monnam(mdef)); if (resists_cold(mdef)) { shieldeff(mdef->mx, mdef->my); @@ -1209,6 +1337,10 @@ tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD); break; case AD_ELEC: + if (negated) { + tmp = 0; + break; + } if (!Blind) pline("%s is zapped!", Monnam(mdef)); tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC); if (resists_elec(mdef)) { @@ -1265,8 +1397,8 @@ tmp = 0; break; case AD_TLPT: - if(tmp <= 0) tmp = 1; - if(tmp < mdef->mhp) { + if (tmp <= 0) tmp = 1; + if (!negated && tmp < mdef->mhp) { char nambuf[BUFSZ]; boolean u_saw_mon = canseemon(mdef); /* record the name before losing sight of monster */ @@ -1303,7 +1435,7 @@ tmp = 0; break; case AD_DRLI: - if (rn2(2) && !resists_drli(mdef)) { + if (!negated && !rn2(3) && !resists_drli(mdef)) { int xtmp = d(2,6); pline("%s suddenly seems weaker!", Monnam(mdef)); mdef->mhpmax -= xtmp; @@ -1312,8 +1444,8 @@ xkilled(mdef,0); } else mdef->m_lev--; + tmp = 0; } - tmp = 0; break; case AD_RUST: if (pd == &mons[PM_IRON_GOLEM]) { @@ -1339,7 +1471,7 @@ case AD_DRST: case AD_DRDX: case AD_DRCO: - if (!rn2(8)) { + if (!negated && !rn2(8)) { Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk)); if (resists_poison(mdef)) pline_The("poison doesn't seem to affect %s.", @@ -1398,7 +1530,7 @@ exercise(A_WIS, TRUE); break; case AD_STCK: - if (!sticks(mdef->data)) + if (!negated && !sticks(mdef->data)) u.ustuck = mdef; /* it's now stuck to you */ break; case AD_WRAP: @@ -1413,7 +1545,8 @@ } } else if(u.ustuck == mdef) { /* Monsters don't wear amulets of magical breathing */ - if (is_pool(u.ux,u.uy) && !is_swimmer(mdef->data)) { + if (is_pool(u.ux,u.uy) && !is_swimmer(mdef->data) && + !amphibious(mdef->data)) { You("drown %s...", mon_nam(mdef)); tmp = mdef->mhp; } else if(mattk->aatyp == AT_HUGS) @@ -1428,36 +1561,56 @@ } else tmp = 0; break; case AD_PLYS: - if (mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) { + if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) { if (!Blind) pline("%s is frozen by you!", Monnam(mdef)); mdef->mcanmove = 0; mdef->mfrozen = rnd(10); } break; case AD_SLEE: - if (!mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) { + if (!negated && !mdef->msleeping && + sleep_monst(mdef, rnd(10), -1)) { if (!Blind) pline("%s is put to sleep by you!", Monnam(mdef)); slept_monst(mdef); } break; case AD_SLIM: - if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] && - mdef->data != &mons[PM_FIRE_ELEMENTAL] && - mdef->data != &mons[PM_SALAMANDER] && - mdef->data != &mons[PM_GREEN_SLIME]) { - You("turn %s into slime.", mon_nam(mdef)); - (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE); - tmp = 0; - } - break; + if (negated) break; /* physical damage only */ + if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] && + mdef->data != &mons[PM_FIRE_ELEMENTAL] && + mdef->data != &mons[PM_SALAMANDER] && + mdef->data != &mons[PM_GREEN_SLIME]) { + You("turn %s into slime.", mon_nam(mdef)); + (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE); + tmp = 0; + } + break; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ - /* There's no msomearmor() function, so just do damage */ - break; + /* there's no msomearmor() function, so just do damage */ + /* if (negated) break; */ + break; + case AD_SLOW: + if (!negated && mdef->mspeed != MSLOW) { + unsigned int oldspeed = mdef->mspeed; + + mon_adjust_speed(mdef, -1, (struct obj *)0); + if (mdef->mspeed != oldspeed && canseemon(mdef)) + pline("%s slows down.", Monnam(mdef)); + } + break; + case AD_CONF: + if (!mdef->mconf) { + if (canseemon(mdef)) + pline("%s looks confused.", Monnam(mdef)); + mdef->mconf = 1; + } + break; default: tmp = 0; - break; + break; } + mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */ if((mdef->mhp -= tmp) < 1) { if (mdef->mtame && !cansee(mdef->mx,mdef->my)) { You_feel("embarrassed for a moment."); @@ -1573,8 +1726,7 @@ for (otmp = mdef->minvent; otmp; otmp = otmp->nobj) (void) snuff_lit(otmp); - if((!touch_petrifies(mdef->data) || Stone_resistance) && - (Unchanging || mdef->data != &mons[PM_GREEN_SLIME])) { + if(!touch_petrifies(mdef->data) || Stone_resistance) { #ifdef LINT /* static char msgbuf[BUFSZ]; */ char msgbuf[BUFSZ]; #else @@ -1636,6 +1788,14 @@ nomul(-tmp); nomovemsg = msgbuf; } else pline("%s", msgbuf); + if (mdef->data == &mons[PM_GREEN_SLIME]) { + Sprintf(msgbuf, "%s isn't sitting well with you.", + The(mdef->data->mname)); + if (!Unchanging) { + Slimed = 5L; + flags.botl = 1; + } + } else exercise(A_CON, TRUE); } end_engulf(); @@ -1910,8 +2070,10 @@ impossible("strange attack of yours (%d)", mattk->aatyp); } - if (dhit == -1) + if (dhit == -1) { + u.mh = -1; /* dead in the current form */ rehumanize(); + } if (sum[i] == 2) return((boolean)passive(mon, 1, 0, mattk->aatyp)); /* defender dead */ @@ -1976,21 +2138,26 @@ exercise(A_STR, FALSE); break; case AD_STON: - if(mhit) { - /* mhit does not mean you physically hit; it just means the - attack was successful */ - if ((aatyp == AT_KICK && !uarmf) || - ((aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC - || aatyp == AT_TUCH) && !uwep && !uarmg) || - aatyp == AT_BITE || aatyp == AT_STNG || aatyp == AT_BUTT || - aatyp == AT_TENT || aatyp == AT_HUGS || aatyp == AT_ENGL) { - if (!Stone_resistance && - !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { + if (mhit) { /* successful attack */ + long protector = attk_protection((int)aatyp); + + /* hero using monsters' AT_MAGC attack is hitting hand to + hand rather than casting a spell */ + if (aatyp == AT_MAGC) protector = W_ARMG; + + if (protector == 0L || /* no protection */ + (protector == W_ARMG && !uarmg && !uwep) || + (protector == W_ARMF && !uarmf) || + (protector == W_ARMH && !uarmh) || + (protector == (W_ARMC|W_ARMG) && (!uarmc || !uarmg))) { + if (!Stone_resistance && + !(poly_when_stoned(youmonst.data) && + polymon(PM_STONE_GOLEM))) { You("turn to stone..."); done_in_by(mon); return 2; + } } - } } break; case AD_RUST: @@ -2239,13 +2406,13 @@ if (Blind) Your("%s stop tingling.", hands); else - Your("%s stop glowing %s.", hands, hcolor(red)); + Your("%s stop glowing %s.", hands, hcolor(NH_RED)); } else { if (Blind) pline_The("tingling in your %s lessens.", hands); else Your("%s no longer glow so brightly %s.", hands, - hcolor(red)); + hcolor(NH_RED)); } u.umconf--; } diff -Naurd ../nethack-3.4.0/src/vault.c ./src/vault.c --- ../nethack-3.4.0/src/vault.c Wed Mar 20 23:43:20 2002 +++ ./src/vault.c Mon Feb 24 15:25:05 2003 @@ -133,7 +133,7 @@ int dummy; /* hack to avoid schain botch */ #endif struct monst *guard; - int vaultroom = (int)vault_occupied(u.urooms); + int trycount, vaultroom = (int)vault_occupied(u.urooms); if(!vaultroom) { u.uinvault = 0; @@ -234,31 +234,38 @@ EGD(guard)->vroom = vaultroom; EGD(guard)->warncnt = 0; - if(!cansee(guard->mx, guard->my)) { - mongone(guard); - return; - } - reset_faint(); /* if fainted - wake up */ - pline("Suddenly one of the Vault's %s enters!", - makeplural(g_monnam(guard))); + if (canspotmon(guard)) + pline("Suddenly one of the Vault's %s enters!", + makeplural(g_monnam(guard))); + else + pline("Someone else has entered the Vault."); newsym(guard->mx,guard->my); - if ((youmonst.m_ap_type == M_AP_OBJECT && - youmonst.mappearance == GOLD_PIECE) || u.uundetected) { - /* You're mimicking a pile of gold or you're hidden. */ + if (youmonst.m_ap_type == M_AP_OBJECT || u.uundetected) { + if (youmonst.m_ap_type == M_AP_OBJECT && + youmonst.mappearance != GOLD_PIECE) + verbalize("Hey! Who left that %s in here?", mimic_obj_name(&youmonst)); + /* You're mimicking some object or you're hidden. */ pline("Puzzled, %s turns around and leaves.", mhe(guard)); mongone(guard); return; } - if (Strangled || is_silent(youmonst.data)) { + if (Strangled || is_silent(youmonst.data) || multi < 0) { + /* [we ought to record whether this this message has already + been given in order to vary it upon repeat visits, but + discarding the monster and its egd data renders that hard] */ verbalize("I'll be back when you're ready to speak to me!"); mongone(guard); return; } + stop_occupation(); /* if occupied, stop it *now* */ + if (multi > 0) { nomul(0); unmul((char *)0); } + trycount = 5; do { - getlin("\"Hello stranger, who are you?\" -",buf); - } while (!letter(buf[0])); + getlin("\"Hello stranger, who are you?\" -", buf); + (void) mungspaces(buf); + } while (!letter(buf[0]) && --trycount > 0); if (u.ualign.type == A_LAWFUL && /* ignore trailing text, in case player includes character's rank */ @@ -362,20 +369,24 @@ wallify_vault(grd) struct monst *grd; { - int x, y; + int x, y, typ; int vlt = EGD(grd)->vroom; char tmp_viz; - xchar lowx = rooms[vlt].lx, hix = rooms[vlt].hx; - xchar lowy = rooms[vlt].ly, hiy = rooms[vlt].hy; - register struct obj *gold; - register boolean fixed = FALSE; - register boolean movedgold = FALSE; + xchar lox = rooms[vlt].lx - 1, hix = rooms[vlt].hx + 1, + loy = rooms[vlt].ly - 1, hiy = rooms[vlt].hy + 1; + struct monst *mon; + struct obj *gold; + struct trap *trap; + boolean fixed = FALSE; + boolean movedgold = FALSE; - for(x = lowx-1; x <= hix+1; x++) - for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) { - if(!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) { - if(MON_AT(x, y) && grd->mx != x && grd->my != y) { - struct monst *mon = m_at(x,y); + for (x = lox; x <= hix; x++) + for (y = loy; y <= hiy; y++) { + /* if not on the room boundary, skip ahead */ + if (x != lox && x != hix && y != loy && y != hiy) continue; + + if (!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) { + if ((mon = m_at(x, y)) != 0 && mon != grd) { if (mon->mtame) yelp(mon); rloc(mon); } @@ -383,16 +394,17 @@ move_gold(gold, EGD(grd)->vroom); movedgold = TRUE; } - if(x == lowx-1 && y == lowy-1) - levl[x][y].typ = TLCORNER; - else if(x == hix+1 && y == lowy-1) - levl[x][y].typ = TRCORNER; - else if(x == lowx-1 && y == hiy+1) - levl[x][y].typ = BLCORNER; - else if(x == hix+1 && y == hiy+1) - levl[x][y].typ = BRCORNER; - else levl[x][y].typ = HWALL; - + if ((trap = t_at(x, y)) != 0) + deltrap(trap); + if (x == lox) + typ = (y == loy) ? TLCORNER : + (y == hiy) ? BLCORNER : VWALL; + else if (x == hix) + typ = (y == loy) ? TRCORNER : + (y == hiy) ? BRCORNER : VWALL; + else /* not left or right side, must be top or bottom */ + typ = HWALL; + levl[x][y].typ = typ; levl[x][y].doormask = 0; /* * hack: player knows walls are restored because of the @@ -406,28 +418,6 @@ fixed = TRUE; } } - for(x = lowx-1; x <= hix+1; x += (hix-lowx+2)) - for(y = lowy; y <= hiy; y++) { - if(!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) { - if(MON_AT(x, y) && grd->mx != x && grd->my != y) { - struct monst *mon = m_at(x,y); - if (mon->mtame) yelp(mon); - rloc(mon); - } - if ((gold = g_at(x, y)) != 0) { - move_gold(gold, EGD(grd)->vroom); - movedgold = TRUE; - } - levl[x][y].typ = VWALL; - levl[x][y].doormask = 0; - tmp_viz = viz_array[y][x]; - viz_array[y][x] = IN_SIGHT|COULD_SEE; - newsym(x,y); - viz_array[y][x] = tmp_viz; - block_point(x,y); - fixed = TRUE; - } - } if(movedgold || fixed) { if(in_fcorridor(grd, grd->mx, grd->my) || cansee(grd->mx, grd->my)) @@ -464,6 +454,8 @@ long umoney = money_cnt(invent); register boolean u_carry_gold = ((umoney + hidden_gold()) > 0L); #endif + boolean see_guard; + if(!on_level(&(egrd->gdlevel), &u.uz)) return(-1); nx = ny = m = n = 0; if(!u_in_vault && !grd_in_vault) @@ -720,6 +712,7 @@ cleanup: x = grd->mx; y = grd->my; + see_guard = canspotmon(grd); wallify_vault(grd); remove_monster(grd->mx, grd->my); newsym(grd->mx,grd->my); @@ -729,7 +722,7 @@ restfakecorr(grd); if(!semi_dead && (in_fcorridor(grd, u.ux, u.uy) || cansee(x, y))) { - if (!disappear_msg_seen) + if (!disappear_msg_seen && see_guard) pline("Suddenly, the %s disappears.", g_monnam(grd)); return(1); } @@ -795,7 +788,7 @@ #else for (coins = invent; coins; coins = nextcoins) { nextcoins = coins->nobj; - if (objects[coins->otyp].oc_class == GOLD_CLASS) { + if (objects[coins->otyp].oc_class == COIN_CLASS) { freeinv(coins); place_object(coins, gx, gy); stackobj(coins); diff -Naurd ../nethack-3.4.0/src/version.c ./src/version.c --- ../nethack-3.4.0/src/version.c Wed Mar 20 23:43:20 2002 +++ ./src/version.c Mon Feb 24 15:25:05 2003 @@ -14,12 +14,21 @@ #include "patchlevel.h" #endif +/* #define BETA_INFO "" */ + /* fill and return the given buffer with the nethack version string */ char * getversionstring(buf) char *buf; { - return strcpy(buf, VERSION_ID); + Strcpy(buf, VERSION_ID); +#if defined(BETA) && defined(BETA_INFO) + Sprintf(eos(buf), " %s", BETA_INFO); +#endif +#if defined(RUNTIME_PORT_ID) + append_port_id(buf); +#endif + return buf; } int @@ -27,7 +36,7 @@ { char buf[BUFSZ]; - pline(getversionstring(buf)); + pline("%s", getversionstring(buf)); return 0; } @@ -64,7 +73,13 @@ if (complain) pline("Version mismatch for file \"%s\".", filename); return FALSE; - } else if (version_data->feature_set != VERSION_FEATURES || + } else if ( +#ifndef IGNORED_FEATURES + version_data->feature_set != VERSION_FEATURES || +#else + (version_data->feature_set & ~IGNORED_FEATURES) != + (VERSION_FEATURES & ~IGNORED_FEATURES) || +#endif version_data->entity_count != VERSION_SANITY1 || version_data->struct_sizes != VERSION_SANITY2) { if (complain) @@ -106,7 +121,7 @@ store_version(fd) int fd; { - static struct version_info version_data = { + const static struct version_info version_data = { VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2 }; diff -Naurd ../nethack-3.4.0/src/weapon.c ./src/weapon.c --- ../nethack-3.4.0/src/weapon.c Wed Mar 20 23:43:21 2002 +++ ./src/weapon.c Mon Feb 24 15:25:05 2003 @@ -56,7 +56,7 @@ }; /* note: entry [0] isn't used */ -STATIC_VAR NEARDATA const char *odd_skill_names[] = { +STATIC_VAR NEARDATA const char * const odd_skill_names[] = { "no skill", "bare hands", /* use barehands_or_martial[] instead */ "two weapon combat", @@ -74,12 +74,12 @@ "matter spells", }; /* indexed vis `is_martial() */ -STATIC_VAR NEARDATA const char *barehands_or_martial[] = { +STATIC_VAR NEARDATA const char * const barehands_or_martial[] = { "bare handed combat", "martial arts" }; -STATIC_OVL -void give_may_advance_msg(skill) +STATIC_OVL void +give_may_advance_msg(skill) int skill; { You_feel("more confident in your %sskills.", @@ -286,13 +286,6 @@ otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) { int bonus = 0; -#ifdef STEED - /* KMH -- Lances are especially made for riding */ - if (otmp == uwep && u.usteed && - objects[otmp->otyp].oc_skill == P_LANCE) - bonus += d(2,10); -#endif - if (otmp->blessed && (is_undead(ptr) || is_demon(ptr))) bonus += rnd(4); if (is_axe(otmp) && is_wooden(ptr)) @@ -472,7 +465,7 @@ } /* Weapons in order of preference */ -static NEARDATA short hwep[] = { +static const NEARDATA short hwep[] = { CORPSE, /* cockatrice corpse */ TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE, KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD, @@ -527,18 +520,18 @@ } /* Called after polymorphing a monster, robbing it, etc.... Monsters - * otherwise never unwield stuff on their own. Shouldn't print messages. + * otherwise never unwield stuff on their own. Might print message. */ void -possibly_unwield(mon) -register struct monst *mon; +possibly_unwield(mon, polyspot) +struct monst *mon; +boolean polyspot; { - register struct obj *obj; - struct obj *mw_tmp; + struct obj *obj, *mw_tmp; if (!(mw_tmp = MON_WEP(mon))) return; - for(obj=mon->minvent; obj; obj=obj->nobj) + for (obj = mon->minvent; obj; obj = obj->nobj) if (obj == mw_tmp) break; if (!obj) { /* The weapon was stolen or destroyed */ MON_NOWEP(mon); @@ -550,13 +543,16 @@ MON_NOWEP(mon); mon->weapon_check = NO_WEAPON_WANTED; obj_extract_self(obj); - /* flooreffects unnecessary, can't wield boulders */ - place_object(obj, mon->mx, mon->my); - stackobj(obj); if (cansee(mon->mx, mon->my)) { - pline("%s drops %s.", Monnam(mon), - distant_name(obj, doname)); - newsym(mon->mx, mon->my); + pline("%s drops %s.", Monnam(mon), + distant_name(obj, doname)); + newsym(mon->mx, mon->my); + } + /* might be dropping object into water or lava */ + if (!flooreffects(obj, mon->mx, mon->my, "drop")) { + if (polyspot) bypass_obj(obj); + place_object(obj, mon->mx, mon->my); + stackobj(obj); } return; } @@ -575,6 +571,7 @@ */ if (!(mw_tmp->cursed && mon->weapon_check == NO_WEAPON_WANTED)) mon->weapon_check = NEED_WEAPON; + return; } /* Let a monster try to wield a weapon, based on mon->weapon_check. @@ -599,7 +596,23 @@ case NEED_PICK_AXE: obj = m_carrying(mon, PICK_AXE); /* KMH -- allow other picks */ - if (!obj) obj = m_carrying(mon, DWARVISH_MATTOCK); + if (!obj && !which_armor(mon, W_ARMS)) + obj = m_carrying(mon, DWARVISH_MATTOCK); + break; + case NEED_AXE: + /* currently, only 2 types of axe */ + obj = m_carrying(mon, BATTLE_AXE); + if (!obj || which_armor(mon, W_ARMS)) + obj = m_carrying(mon, AXE); + break; + case NEED_PICK_OR_AXE: + /* prefer pick for fewer switches on most levels */ + obj = m_carrying(mon, DWARVISH_MATTOCK); + if (!obj) obj = m_carrying(mon, BATTLE_AXE); + if (!obj || which_armor(mon, W_ARMS)) { + obj = m_carrying(mon, PICK_AXE); + if (!obj) obj = m_carrying(mon, AXE); + } break; default: impossible("weapon_check %d for %s?", mon->weapon_check, mon_nam(mon)); @@ -819,7 +832,7 @@ P_NAME(skill)); } -static struct skill_range { +const static struct skill_range { short first, last; const char *name; } skill_ranges[] = { @@ -871,7 +884,7 @@ /* start with a legend if any entries will be annotated with "*" or "#" below */ if (eventually_advance > 0 || maxxed_cnt > 0) { - any.a_int = 0; + any.a_void = 0; if (eventually_advance > 0) { Sprintf(buf, "(Skill%s flagged by \"*\" may be enhanced %s.)", @@ -1221,7 +1234,7 @@ */ void skill_init(class_skill) -struct def_skill *class_skill; +const struct def_skill *class_skill; { struct obj *obj; int skmax, skill; diff -Naurd ../nethack-3.4.0/src/were.c ./src/were.c --- ../nethack-3.4.0/src/were.c Wed Mar 20 23:43:21 2002 +++ ./src/were.c Mon Feb 24 15:25:05 2003 @@ -83,7 +83,7 @@ mon->mhp += (mon->mhpmax - mon->mhp) / 4; newsym(mon->mx,mon->my); mon_break_armor(mon, FALSE); - possibly_unwield(mon); + possibly_unwield(mon, FALSE); } boolean diff -Naurd ../nethack-3.4.0/src/wield.c ./src/wield.c --- ../nethack-3.4.0/src/wield.c Wed Mar 20 23:43:21 2002 +++ ./src/wield.c Mon Feb 24 15:25:05 2003 @@ -52,14 +52,6 @@ STATIC_DCL int FDECL(ready_weapon, (struct obj *)); -/* elven weapons vibrate warningly when enchanted beyond a limit */ -#define is_elven_weapon(optr) ((optr)->otyp == ELVEN_ARROW\ - || (optr)->otyp == ELVEN_SPEAR\ - || (optr)->otyp == ELVEN_DAGGER\ - || (optr)->otyp == ELVEN_SHORT_SWORD\ - || (optr)->otyp == ELVEN_BROADSWORD\ - || (optr)->otyp == ELVEN_BOW) - /* used by will_weld() */ /* probably should be renamed */ #define erodeable_wep(optr) ((optr)->oclass == WEAPON_CLASS \ @@ -260,6 +252,8 @@ return (0); } else if (welded(uwep)) { weldmsg(uwep); + /* previously interrupted armor removal mustn't be resumed */ + reset_remarm(); return (0); } @@ -337,18 +331,20 @@ dowieldquiver() { register struct obj *newquiver; - + const char *quivee_types = (uslinging() || + (uswapwep && objects[uswapwep->otyp].oc_skill == P_SLING)) ? + bullets : ready_objs; /* Since the quiver isn't in your hands, don't check cantwield(), */ /* will_weld(), touch_petrifies(), etc. */ multi = 0; /* Because 'Q' used to be quit... */ - if (!flags.suppress_alert || flags.suppress_alert < FEATURE_NOTICE_VER(3,3,0)) + if (flags.suppress_alert < FEATURE_NOTICE_VER(3,3,0)) pline("Note: Please use #quit if you wish to exit the game."); /* Prompt for a new quiver */ - if (!(newquiver = getobj(uslinging() ? bullets : ready_objs, "ready"))) + if (!(newquiver = getobj(quivee_types, "ready"))) /* Cancelled */ return (0); @@ -401,15 +397,88 @@ return (0); } +/* used for #rub and for applying pick-axe, whip, grappling hook, or polearm */ +/* (moved from apply.c) */ +boolean +wield_tool(obj, verb) +struct obj *obj; +const char *verb; /* "rub",&c */ +{ + const char *what; + boolean more_than_1; + + if (obj == uwep) return TRUE; /* nothing to do if already wielding it */ + + if (!verb) verb = "wield"; + what = xname(obj); + more_than_1 = (obj->quan > 1L || + strstri(what, "pair of ") != 0 || + strstri(what, "s of ") != 0); + + if (obj->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL)) { + char yourbuf[BUFSZ]; + + You_cant("%s %s %s while wearing %s.", + verb, shk_your(yourbuf, obj), what, + more_than_1 ? "them" : "it"); + return FALSE; + } + if (welded(uwep)) { + if (flags.verbose) { + const char *hand = body_part(HAND); + + if (bimanual(uwep)) hand = makeplural(hand); + if (strstri(what, "pair of ") != 0) more_than_1 = FALSE; + pline( + "Since your weapon is welded to your %s, you cannot %s %s %s.", + hand, verb, more_than_1 ? "those" : "that", xname(obj)); + } else { + You_cant("do that."); + } + return FALSE; + } + if (cantwield(youmonst.data)) { + You_cant("hold %s strongly enough.", more_than_1 ? "them" : "it"); + return FALSE; + } + /* check shield */ + if (uarms && bimanual(obj)) { + You("cannot %s a two-handed %s while wearing a shield.", + verb, (obj->oclass == WEAPON_CLASS) ? "weapon" : "tool"); + return FALSE; + } + if (uquiver == obj) setuqwep((struct obj *)0); + if (uswapwep == obj) { + (void) doswapweapon(); + /* doswapweapon might fail */ + if (uswapwep == obj) return FALSE; + } else { + You("now wield %s.", doname(obj)); + setuwep(obj); + } + if (uwep != obj) return FALSE; /* rewielded old object after dying */ + /* applying weapon or tool that gets wielded ends two-weapon combat */ + if (u.twoweap) + untwoweapon(); + if (obj->oclass != WEAPON_CLASS) + unweapon = TRUE; + return TRUE; +} + int can_twoweapon() { struct obj *otmp; #define NOT_WEAPON(obj) (!is_weptool(obj) && obj->oclass != WEAPON_CLASS) - if (!could_twoweap(youmonst.data)) - You_cant("use two weapons in your current form."); - else if (!uwep || !uswapwep) + if (!could_twoweap(youmonst.data)) { + if (Upolyd) + You_cant("use two weapons in your current form."); + else + pline("%s aren't able to use two weapons at once.", + makeplural((flags.female && urole.name.f) ? + urole.name.f : urole.name.m)); + } else if (!uwep || !uswapwep) Your("%s%s%s empty.", uwep ? "left " : uswapwep ? "right " : "", body_part(HAND), (!uwep && !uswapwep) ? "s are" : " is"); else if (NOT_WEAPON(uwep) || NOT_WEAPON(uswapwep)) { @@ -433,20 +502,26 @@ Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname)); instapetrify(kbuf); } else if (Glib || uswapwep->cursed) { - char str[BUFSZ]; - struct obj *obj = uswapwep; - - /* Avoid trashing makeplural's static buffer */ - Strcpy(str, makeplural(body_part(HAND))); - Your("%s from your %s!", aobjnam(obj, "slip"), str); if (!Glib) - obj->bknown = TRUE; - dropx(obj); + uswapwep->bknown = TRUE; + drop_uswapwep(); } else return (TRUE); return (FALSE); } +void +drop_uswapwep() +{ + char str[BUFSZ]; + struct obj *obj = uswapwep; + + /* Avoid trashing makeplural's static buffer */ + Strcpy(str, makeplural(body_part(HAND))); + Your("%s from your %s!", aobjnam(obj, "slip"), str); + dropx(obj); +} + int dotwoweapon() { @@ -613,8 +688,9 @@ register struct obj *otmp; register int amount; { - register const char *color = hcolor((amount < 0) ? Black : blue); - register const char *xtime; + const char *color = hcolor((amount < 0) ? NH_BLACK : NH_BLUE); + const char *xtime; + int otyp = STRANGE_OBJECT; if(!uwep || (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep))) { char buf[BUFSZ]; @@ -626,11 +702,14 @@ return(0); } + if (otmp && otmp->oclass == SCROLL_CLASS) otyp = otmp->otyp; + if(uwep->otyp == WORM_TOOTH && amount >= 0) { uwep->otyp = CRYSKNIFE; uwep->oerodeproof = 0; Your("weapon seems sharper now."); uwep->cursed = 0; + if (otyp != STRANGE_OBJECT) makeknown(otyp); return(1); } @@ -638,6 +717,7 @@ uwep->otyp = WORM_TOOTH; uwep->oerodeproof = 0; Your("weapon seems duller now."); + if (otyp != STRANGE_OBJECT && otmp->bknown) makeknown(otyp); return(1); } @@ -656,9 +736,7 @@ else Your("%s.", aobjnam(uwep, "evaporate")); - while(uwep) /* let all of them disappear */ - /* note: uwep->quan = 1 is nogood if unpaid */ - useup(uwep); + useupall(uwep); /* let all of them disappear */ return(1); } if (!Blind) { @@ -666,6 +744,9 @@ Your("%s %s for a %s.", aobjnam(uwep, amount == 0 ? "violently glow" : "glow"), color, xtime); + if (otyp != STRANGE_OBJECT && uwep->known && + (amount > 0 || (amount < 0 && otmp->bknown))) + makeknown(otyp); } uwep->spe += amount; if(amount > 0) uwep->cursed = 0; @@ -682,6 +763,7 @@ } /* an elven magic clue, cookie@keebler */ + /* elven weapons vibrate warningly when enchanted beyond a limit */ if ((uwep->spe > 5) && (is_elven_weapon(uwep) || uwep->oartifact || !rn2(7))) Your("%s unexpectedly.", diff -Naurd ../nethack-3.4.0/src/wizard.c ./src/wizard.c --- ../nethack-3.4.0/src/wizard.c Wed Mar 20 23:43:22 2002 +++ ./src/wizard.c Mon Feb 24 15:25:05 2003 @@ -9,6 +9,9 @@ #include "hack.h" #include "qtext.h" +#include "epri.h" + +extern const int monstr[]; #ifdef OVLB @@ -305,6 +308,7 @@ case STRAT_HEAL: /* hide and recover */ /* if wounded, hole up on or near the stairs (to block them) */ /* unless, of course, there are no stairs (e.g. endlevel) */ + mtmp->mavenge = 1; /* covetous monsters attack while fleeing */ if (In_W_tower(mtmp->mx, mtmp->my, &u.uz) || (mtmp->iswiz && !xupstair && !mon_has_amulet(mtmp))) { if (!rn2(3 + mtmp->mhp/10)) rloc(mtmp); @@ -321,7 +325,7 @@ /* fall through :-) */ case STRAT_NONE: /* harrass */ - if(!rn2(5)) mnexto(mtmp); + if (!rn2(!mtmp->mflee ? 5 : 33)) mnexto(mtmp); return(0); default: /* kill, maim, pillage! */ @@ -361,7 +365,7 @@ return(0); } } else { /* a monster has it - 'port beside it. */ - (void) mnearto(mtmp, tx, ty, TRUE); + (void) mnearto(mtmp, tx, ty, FALSE); return(0); } } @@ -425,7 +429,7 @@ int count=0; if(!rn2(10) && Inhell) { - msummon(&mons[PM_WIZARD_OF_YENDOR]); + msummon((struct monst *) 0); /* summons like WoY */ count++; } else { tmp = (u.ulevel > 3) ? u.ulevel/3 : 1; /* just in case -- rph */ @@ -434,10 +438,20 @@ bypos.y = u.uy; for(i = rnd(tmp); i > 0; --i) for(j=0; j<20; j++) { + int makeindex; + + /* Don't create more spellcasters of the monsters' level or + * higher--avoids chain summoners filling up the level. + */ + do { + makeindex = pick_nasty(); + } while(mcast && attacktype(&mons[makeindex], AT_MAGC) && + monstr[makeindex] >= monstr[mcast->mnum]); + /* do this after picking the monster to place */ if (mcast && - !enexto(&bypos, mcast->mux, mcast->muy, mcast->data)) + !enexto(&bypos, mcast->mux, mcast->muy, &mons[makeindex])) continue; - if ((mtmp = makemon(&mons[pick_nasty()], + if ((mtmp = makemon(&mons[makeindex], bypos.x, bypos.y, NO_MM_FLAGS)) != 0) { mtmp->msleeping = mtmp->mpeaceful = mtmp->mtame = 0; set_malign(mtmp); @@ -516,7 +530,7 @@ break; case 2: if (!Blind) You("notice a %s glow surrounding you.", - hcolor(Black)); + hcolor(NH_BLACK)); rndcurse(); break; case 3: aggravate(); @@ -538,7 +552,7 @@ } } -const char *random_insult[] = { +const char * const random_insult[] = { "antic", "blackguard", "caitiff", @@ -569,7 +583,7 @@ "wretch", }; -const char *random_malediction[] = { +const char * const random_malediction[] = { "Hell shall soon claim thy remains,", "I chortle at thee, thou pathetic", "Prepare to die, thou", @@ -608,7 +622,7 @@ verbalize("%s %s!", random_malediction[rn2(SIZE(random_malediction))], random_insult[rn2(SIZE(random_insult))]); - } else if(is_lminion(mtmp->data)) { + } else if(is_lminion(mtmp)) { com_pager(rn2(QTN_ANGELIC - 1 + (Hallucination ? 1 : 0)) + QT_ANGELIC); } else { diff -Naurd ../nethack-3.4.0/src/worm.c ./src/worm.c --- ../nethack-3.4.0/src/worm.c Wed Mar 20 23:43:22 2002 +++ ./src/worm.c Mon Feb 24 15:25:05 2003 @@ -613,7 +613,7 @@ do { random_dir(ox, oy, &nx, &ny); - } while (!goodpos(nx, ny, worm) && (tryct++ < 50)); + } while (!goodpos(nx, ny, worm, 0) && (tryct++ < 50)); if (tryct < 50) { place_worm_seg(worm, nx, ny); diff -Naurd ../nethack-3.4.0/src/worn.c ./src/worn.c --- ../nethack-3.4.0/src/worn.c Wed Mar 20 23:43:22 2002 +++ ./src/worn.c Mon Feb 24 15:25:05 2003 @@ -1,11 +1,11 @@ -/* SCCS Id: @(#)worn.c 3.4 2002/02/07 */ +/* SCCS Id: @(#)worn.c 3.4 2003/01/08 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL void FDECL(m_lose_armor, (struct monst *,struct obj *)); -STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long,BOOLEAN_P)); +STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *)); const struct worn { @@ -147,7 +147,7 @@ struct obj *obj; /* item to make known if effect can be seen */ { struct obj *otmp; - boolean give_msg = !in_mklev; + boolean give_msg = !in_mklev, petrify = FALSE; unsigned int oldspeed = mon->mspeed; switch (adjust) { @@ -169,6 +169,11 @@ mon->permspeed = MSLOW; give_msg = FALSE; /* (not currently used) */ break; + case -3: /* petrification */ + /* take away intrinsic speed but don't reduce normal speed */ + if (mon->permspeed == MFAST) mon->permspeed = 0; + petrify = TRUE; + break; } for (otmp = mon->minvent; otmp; otmp = otmp->nobj) @@ -179,12 +184,16 @@ else mon->mspeed = mon->permspeed; - if (give_msg && mon->mspeed != oldspeed && canseemon(mon)) { + if (give_msg && (mon->mspeed != oldspeed || petrify) && canseemon(mon)) { /* fast to slow (skipping intermediate state) or vice versa */ const char *howmuch = (mon->mspeed + oldspeed == MFAST + MSLOW) ? "much " : ""; - if (adjust > 0 || mon->mspeed == MFAST) + if (petrify) { + /* mimic the player's petrification countdown; "slowing down" + even if fast movement rate retained via worn speed boots */ + if (flags.verbose) pline("%s is slowing down.", Monnam(mon)); + } else if (adjust > 0 || mon->mspeed == MFAST) pline("%s is suddenly moving %sfaster.", Monnam(mon), howmuch); else pline("%s seems to be moving %sslower.", Monnam(mon), howmuch); @@ -199,10 +208,10 @@ /* armor put on or taken off; might be magical variety */ void -update_mon_intrinsics(mon, obj, on) +update_mon_intrinsics(mon, obj, on, silently) struct monst *mon; struct obj *obj; -boolean on; +boolean on, silently; { int unseen; uchar mask; @@ -218,8 +227,13 @@ mon->minvis = !mon->invis_blkd; break; case FAST: + { + boolean save_in_mklev = in_mklev; + if (silently) in_mklev = TRUE; mon_adjust_speed(mon, 0, obj); + in_mklev = save_in_mklev; break; + } /* properties handled elsewhere */ case ANTIMAGIC: case REFLECTING: @@ -253,8 +267,13 @@ mon->minvis = mon->perminvis; break; case FAST: + { + boolean save_in_mklev = in_mklev; + if (silently) in_mklev = TRUE; mon_adjust_speed(mon, 0, obj); + in_mklev = save_in_mklev; break; + } case FIRE_RES: case COLD_RES: case SLEEP_RES: @@ -301,7 +320,7 @@ #endif /* if couldn't see it but now can, or vice versa, update display */ - if (unseen ^ !canseemon(mon)) + if (!silently && (unseen ^ !canseemon(mon))) newsym(mon->mx, mon->my); } @@ -341,47 +360,58 @@ register struct monst *mon; boolean creation; { +#define RACE_EXCEPTION TRUE /* Note the restrictions here are the same as in dowear in do_wear.c * except for the additional restriction on intelligence. (Players * are always intelligent, even if polymorphed). */ if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data)) return; - /* give mummies a chance to wear their wrappings */ - if (mindless(mon->data) && (mon->data->mlet != S_MUMMY || !creation)) + /* give mummies a chance to wear their wrappings + * and let skeletons wear their initial armor */ + if (mindless(mon->data) && (!creation || + (mon->data->mlet != S_MUMMY && mon->data != &mons[PM_SKELETON]))) return; - m_dowear_type(mon, W_AMUL, creation); + m_dowear_type(mon, W_AMUL, creation, FALSE); #ifdef TOURIST /* can't put on shirt if already wearing suit */ if (!cantweararm(mon->data) || (mon->misc_worn_check & W_ARM)) - m_dowear_type(mon, W_ARMU, creation); + m_dowear_type(mon, W_ARMU, creation, FALSE); #endif /* treating small as a special case allows hobbits, gnomes, and kobolds to wear cloaks */ if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL) - m_dowear_type(mon, W_ARMC, creation); - m_dowear_type(mon, W_ARMH, creation); + m_dowear_type(mon, W_ARMC, creation, FALSE); + m_dowear_type(mon, W_ARMH, creation, FALSE); if (!MON_WEP(mon) || !bimanual(MON_WEP(mon))) - m_dowear_type(mon, W_ARMS, creation); - m_dowear_type(mon, W_ARMG, creation); + m_dowear_type(mon, W_ARMS, creation, FALSE); + m_dowear_type(mon, W_ARMG, creation, FALSE); if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR) - m_dowear_type(mon, W_ARMF, creation); + m_dowear_type(mon, W_ARMF, creation, FALSE); if (!cantweararm(mon->data)) - m_dowear_type(mon, W_ARM, creation); + m_dowear_type(mon, W_ARM, creation, FALSE); + else + m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION); } STATIC_OVL void -m_dowear_type(mon, flag, creation) +m_dowear_type(mon, flag, creation, racialexception) struct monst *mon; long flag; boolean creation; +boolean racialexception; { struct obj *old, *best, *obj; int m_delay = 0; + int unseen = !canseemon(mon); + char nambuf[BUFSZ]; if (mon->mfrozen) return; /* probably putting previous item on */ + /* Get a copy of monster's name before altering its visibility */ + Strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon)); + old = which_armor(mon, flag); if (old && old->cursed) return; if (old && flag == W_AMUL) return; /* no such thing as better amulets */ @@ -406,6 +436,8 @@ break; case W_ARMH: if (!is_helmet(obj)) continue; + /* (flimsy exception matches polyself handling) */ + if (has_horns(mon->data) && !is_flimsy(obj)) continue; break; case W_ARMS: if (!is_shield(obj)) continue; @@ -418,6 +450,7 @@ break; case W_ARM: if (!is_suit(obj)) continue; + if (racialexception && (racial_exception(mon, obj) < 1)) continue; break; } if (obj->owornmask) continue; @@ -465,11 +498,19 @@ if (mon->mfrozen) mon->mcanmove = 0; } if (old) - update_mon_intrinsics(mon, old, FALSE); + update_mon_intrinsics(mon, old, FALSE, creation); mon->misc_worn_check |= flag; best->owornmask |= flag; - update_mon_intrinsics(mon, best, TRUE); + update_mon_intrinsics(mon, best, TRUE, creation); + /* if couldn't see it but now can, or vice versa, */ + if (!creation && (unseen ^ !canseemon(mon))) { + if (mon->minvis && !See_invisible) { + pline("Suddenly you cannot see %s.", nambuf); + makeknown(best->otyp); + } /* else if (!mon->minvis) pline("%s suddenly appears!", Amonnam(mon)); */ + } } +#undef RACE_EXCEPTION struct obj * which_armor(mon, flag) @@ -490,8 +531,9 @@ struct obj *obj; { mon->misc_worn_check &= ~obj->owornmask; + if (obj->owornmask) + update_mon_intrinsics(mon, obj, FALSE, FALSE); obj->owornmask = 0L; - update_mon_intrinsics(mon, obj, FALSE); obj_extract_self(obj); place_object(obj, mon->mx, mon->my); @@ -499,35 +541,44 @@ newsym(mon->mx, mon->my); } +/* all objects with their bypass bit set should now be reset to normal */ void clear_bypasses() { struct obj *otmp, *nobj; + struct monst *mtmp; for (otmp = fobj; otmp; otmp = nobj) { nobj = otmp->nobj; if (otmp->bypass) { otmp->bypass = 0; + /* bypass will have inhibited any stacking, but since it's + used for polymorph handling, the objects here probably + have been transformed and won't be stacked in the usual + manner afterwards; so don't bother with this */ #if 0 - /* setting otmp->bypass changes mergability. - * If monster can ever drop anything that - * can and should merge, this code block - * should be enabled. - */ - { - struct obj *obj; + if (objects[otmp->otyp].oc_merge) { xchar ox, oy; + (void) get_obj_location(otmp, &ox, &oy, 0); - obj_extract_self(otmp); - obj = merge_choice(fobj, otmp); - /* If it can't merge, then place it */ - if (!obj || (obj && !merged(&obj, &otmp))) - place_object(otmp, ox, oy); + stack_object(otmp); newsym(ox, oy); } -#endif +#endif /*0*/ } } + /* invent and mydogs chains shouldn't matter here */ + for (otmp = migrating_objs; otmp; otmp = otmp->nobj) + otmp->bypass = 0; + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) + otmp->bypass = 0; + } + for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) { + for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) + otmp->bypass = 0; + } flags.bypasses = FALSE; } @@ -547,6 +598,7 @@ register struct obj *otmp; struct permonst *mdat = mon->data; boolean vis = cansee(mon->mx, mon->my); + boolean handless_or_tiny = (nohands(mdat) || verysmall(mdat)); const char *pronoun = mhim(mon), *ppronoun = mhis(mon); @@ -626,12 +678,12 @@ } #endif } - if (nohands(mdat) || verysmall(mdat)) { + if (handless_or_tiny) { + /* [caller needs to handle weapon checks] */ if ((otmp = which_armor(mon, W_ARMG)) != 0) { if (vis) pline("%s drops %s gloves%s!", Monnam(mon), ppronoun, MON_WEP(mon) ? " and weapon" : ""); - possibly_unwield(mon); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } @@ -644,7 +696,11 @@ if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } - if ((otmp = which_armor(mon, W_ARMH)) != 0) { + } + if (handless_or_tiny || has_horns(mdat)) { + if ((otmp = which_armor(mon, W_ARMH)) != 0 && + /* flimsy test for horns matches polyself handling */ + (handless_or_tiny || !is_flimsy(otmp))) { if (vis) pline("%s helmet falls to the %s!", s_suffix(Monnam(mon)), surface(mon->mx, mon->my)); @@ -654,8 +710,7 @@ m_lose_armor(mon, otmp); } } - if (nohands(mdat) || verysmall(mdat) || slithy(mdat) || - mdat->mlet == S_CENTAUR) { + if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) { if ((otmp = which_armor(mon, W_ARMF)) != 0) { if (vis) { if (is_whirly(mon->data)) @@ -711,4 +766,29 @@ } return 0; } + +/* + * Exceptions to things based on race. Correctly checks polymorphed player race. + * Returns: + * 0 No exception, normal rules apply. + * 1 If the race/object combination is acceptable. + * -1 If the race/object combination is unacceptable. + */ +int +racial_exception(mon, obj) +struct monst *mon; +struct obj *obj; +{ + const struct permonst *ptr = raceptr(mon); + + /* Acceptable Exceptions: */ + /* Allow hobbits to wear elven armor - LoTR */ + if (ptr == &mons[PM_HOBBIT] && is_elven_armor(obj)) + return 1; + /* Unacceptable Exceptions: */ + /* Checks for object that certain races should never use go here */ + /* return -1; */ + + return 0; +} /*worn.c*/ diff -Naurd ../nethack-3.4.0/src/write.c ./src/write.c --- ../nethack-3.4.0/src/write.c Wed Mar 20 23:43:22 2002 +++ ./src/write.c Mon Feb 24 15:25:05 2003 @@ -84,9 +84,9 @@ You("need hands to be able to write!"); return 0; } else if (Glib) { - dropx(pen); pline("%s from your %s.", Tobjnam(pen, "slip"), makeplural(body_part(FINGER))); + dropx(pen); return 1; } diff -Naurd ../nethack-3.4.0/src/zap.c ./src/zap.c --- ../nethack-3.4.0/src/zap.c Wed Mar 20 23:43:22 2002 +++ ./src/zap.c Mon Feb 24 15:25:05 2003 @@ -28,7 +28,6 @@ STATIC_DCL int FDECL(zhitm, (struct monst *,int,int,struct obj **)); STATIC_DCL void FDECL(zhitu, (int,int,const char *,XCHAR_P,XCHAR_P)); STATIC_DCL void FDECL(revive_egg, (struct obj *)); -STATIC_DCL boolean FDECL(hits_bars, (struct obj *)); #ifdef STEED STATIC_DCL boolean FDECL(zap_steed, (struct obj *)); #endif @@ -59,11 +58,11 @@ #ifndef OVLB STATIC_VAR const char are_blinded_by_the_flash[]; -extern const char *flash_types[]; +extern const char * const flash_types[]; #else STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!"; -const char *flash_types[] = { /* also used in buzzmu(mcastu.c) */ +const char * const flash_types[] = { /* also used in buzzmu(mcastu.c) */ "magic missile", /* Wands must be 0-9 */ "bolt of fire", "bolt of cold", @@ -110,9 +109,9 @@ boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart; int dmg, otyp = otmp->otyp; const char *zap_type_text = "spell"; -#ifdef STEED struct obj *obj; -#endif + boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC && + mtmp->m_ap_type != M_AP_NOTHING); if (u.uswallow && mtmp == u.ustuck) reveal_invis = FALSE; @@ -188,11 +187,14 @@ pline("%s shudders!", Monnam(mtmp)); makeknown(otyp); } + /* dropped inventory shouldn't be hit by this zap */ + for (obj = mtmp->minvent; obj; obj = obj->nobj) + bypass_obj(obj); /* flags.bypasses = TRUE; ## for make_corpse() */ /* no corpse after system shock */ xkilled(mtmp, 3); } else if (newcham(mtmp, (struct permonst *)0, - (otyp != POT_POLYMORPH))) { + (otyp != POT_POLYMORPH), FALSE)) { if (!Hallucination && canspotmon(mtmp)) makeknown(otyp); } @@ -200,7 +202,7 @@ break; case WAN_CANCELLATION: case SPE_CANCELLATION: - cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE); + (void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE); break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: @@ -243,8 +245,8 @@ #ifdef STEED } else if (!!(obj = which_armor(mtmp, W_SADDLE))) { mtmp->misc_worn_check &= ~obj->owornmask; + update_mon_intrinsics(mtmp, obj, FALSE, FALSE); obj->owornmask = 0L; - update_mon_intrinsics(mtmp, obj, FALSE); obj_extract_self(obj); place_object(obj, mtmp->mx, mtmp->my); /* call stackobj() if we ever drop anything that can merge */ @@ -264,9 +266,18 @@ mtmp->mblinded = 0; mtmp->mcansee = 1; } - if (canseemon(mtmp)) - pline("%s looks%s better.", Monnam(mtmp), - otyp == SPE_EXTRA_HEALING ? " much" : "" ); + if (canseemon(mtmp)) { + if (disguised_mimic) { + if (mtmp->m_ap_type == M_AP_OBJECT && + mtmp->mappearance == STRANGE_OBJECT) { + /* it can do better now */ + set_mimic_sym(mtmp); + newsym(mtmp->mx, mtmp->my); + } else + mimic_hit_msg(mtmp, otyp); + } else pline("%s looks%s better.", Monnam(mtmp), + otyp == SPE_EXTRA_HEALING ? " much" : "" ); + } if (mtmp->mtame || mtmp->mpeaceful) { adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type)); } @@ -294,7 +305,7 @@ if (monsndx(mtmp->data) == PM_STONE_GOLEM) { char *name = Monnam(mtmp); /* turn into flesh golem */ - if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE)) { + if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE, FALSE)) { if (canseemon(mtmp)) pline("%s turns to flesh!", name); } else { @@ -640,7 +651,7 @@ if (canseemon(ghost)) pline("%s is suddenly drawn into its former body!", Monnam(ghost)); - mongone(ghost); + mondead(ghost); recorporealization = TRUE; newsym(x2, y2); } @@ -1191,6 +1202,8 @@ boolean can_merge = (id == STRANGE_OBJECT); int obj_location = obj->where; + if (obj->otyp == BOULDER && In_sokoban(&u.uz)) + change_luck(-1); /* Sokoban guilt */ if (id == STRANGE_OBJECT) { /* preserve symbol */ int try_limit = 3; /* Try up to 3 times to make the magic-or-not status of @@ -1343,7 +1356,7 @@ /* for now, take off worn items being polymorphed */ if (obj_location == OBJ_INVENT) { if (id == STRANGE_OBJECT) - remove_worn_item(obj); + remove_worn_item(obj, TRUE); else { /* This is called only for stone to flesh. It's a lot simpler * than it otherwise might be. We don't need to check for @@ -1351,7 +1364,7 @@ * any) and only three worn masks are possible. */ otmp->owornmask = obj->owornmask; - remove_worn_item(obj); + remove_worn_item(obj, TRUE); setworn(otmp, otmp->owornmask); if (otmp->owornmask & LEFT_RING) uleft = otmp; @@ -1427,6 +1440,7 @@ struct obj *obj, *otmp; { int res = 1; /* affected object by default */ + xchar refresh_x, refresh_y; if (obj->bypass) { /* The bypass bit is currently only used as follows: @@ -1582,6 +1596,7 @@ res = 0; break; case SPE_STONE_TO_FLESH: + refresh_x = obj->ox; refresh_y = obj->oy; if (objects[obj->otyp].oc_material != MINERAL && objects[obj->otyp].oc_material != GEMSTONE) { res = 0; @@ -1592,15 +1607,15 @@ case ROCK_CLASS: /* boulders and statues */ if (obj->otyp == BOULDER) { obj = poly_obj(obj, HUGE_CHUNK_OF_MEAT); - if (In_sokoban(&u.uz)) - change_luck(-1); /* Sokoban guilt */ goto smell; } else if (obj->otyp == STATUE) { xchar oox, ooy; (void) get_obj_location(obj, &oox, &ooy, 0); + refresh_x = oox; refresh_y = ooy; if (!animate_statue(obj, oox, ooy, ANIMATE_SPELL, (int *)0)) { + struct obj *item; makecorpse: if (mons[obj->corpsenm].geno & (G_NOCORPSE|G_UNIQ)) { res = 0; @@ -1608,7 +1623,12 @@ } /* Unlikely to get here since genociding * monsters also sets the G_NOCORPSE flag. + * Drop the contents, poly_obj looses them. */ + while ((item = obj->cobj) != 0) { + obj_extract_self(item); + place_object(item, oox, ooy); + } obj = poly_obj(obj, CORPSE); break; } @@ -1627,6 +1647,7 @@ break; } (void) get_obj_location(obj, &oox, &ooy, 0); + refresh_x = oox; refresh_y = ooy; mon = makemon(&mons[obj->corpsenm], oox, ooy, NO_MM_FLAGS); if (mon) { @@ -1657,7 +1678,7 @@ res = 0; break; } - newsym(obj->ox,obj->oy); + newsym(refresh_x, refresh_y); break; default: impossible("What an interesting effect (%d)", otmp->otyp); @@ -1684,8 +1705,9 @@ because that last call might end up operating on our `next_obj' (below), rather than on the current object, if it happens to encounter a statue which mustn't become animated. */ - if (t && t->ttyp == STATUE_TRAP) - (void) activate_statue_trap(t, tx, ty, TRUE); + if (t && t->ttyp == STATUE_TRAP && + activate_statue_trap(t, tx, ty, TRUE) && obj->otyp == WAN_STRIKING) + makeknown(obj->otyp); } poly_zapped = -1; @@ -1934,7 +1956,7 @@ case WAN_CANCELLATION: case SPE_CANCELLATION: - cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE); + (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE); break; case SPE_DRAIN_LIFE: @@ -2181,7 +2203,7 @@ * effect is too strong. currently non-hero monsters do not zap * themselves with cancellation. */ -void +boolean cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel) register struct monst *mdef; register struct obj *obj; @@ -2194,7 +2216,7 @@ if (youdefend ? (!youattack && Antimagic) : resist(mdef, obj->oclass, 0, NOTELL)) - return; /* resisted cancellation */ + return FALSE; /* resisted cancellation */ if (self_cancel) { /* 1st cancel inventory */ struct obj *otmp; @@ -2213,7 +2235,11 @@ if (Upolyd) { if ((u.umonnum == PM_CLAY_GOLEM) && !Blind) pline(writing_vanishes, your); - rehumanize(); + + if (Unchanging) + Your("amulet grows hot for a moment, then cools."); + else + rehumanize(); } } else { mdef->mcan = TRUE; @@ -2233,6 +2259,7 @@ } } } + return TRUE; } /* you've zapped an immediate type wand up or down */ @@ -2549,25 +2576,6 @@ #endif /*OVL0*/ #ifdef OVL1 -/* return TRUE if obj_type can't pass through iron bars */ -static boolean -hits_bars(obj) -struct obj *obj; -{ - int obj_type = obj->otyp; - /* - There should be a _lot_ of things here..., but iron ball - started this change and boulders, chests, and boxes were added later... - Corpses and statues that are at least medium size are also screened. - */ - if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL || obj_type == LARGE_BOX || - obj_type == CHEST || obj_type == ICE_BOX || - ((obj_type == CORPSE || obj_type == STATUE) - && mons[obj->corpsenm].msize >= MZ_MEDIUM)) - return TRUE; - return FALSE; -} - /* * Called for the following distance effects: * when a weapon is thrown (weapon == THROWN_WEAPON) @@ -2594,9 +2602,9 @@ FDECL((*fhito), (OBJ_P, OBJ_P)); struct obj *obj; /* object tossed/used */ { - register struct monst *mtmp; - register uchar typ; - register boolean shopdoor = FALSE; + struct monst *mtmp; + uchar typ; + boolean shopdoor = FALSE, point_blank = TRUE; if (weapon == KICKED_WEAPON) { /* object starts one square in front of player */ @@ -2635,8 +2643,11 @@ typ = levl[bhitpos.x][bhitpos.y].typ; /* iron bars will block anything big enough */ - if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) - && typ == IRONBARS && hits_bars(obj)) { + if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) && + typ == IRONBARS && + hits_bars(&obj, x - ddx, y - ddy, + point_blank ? 0 : !rn2(5), 1)) { + /* caveat: obj might now be null... */ bhitpos.x -= ddx; bhitpos.y -= ddy; break; @@ -2713,13 +2724,11 @@ if(bhitpile(obj,fhito,bhitpos.x,bhitpos.y)) range--; } else { -boolean costly = shop_keeper(*in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) && - costly_spot(bhitpos.x, bhitpos.y); - if(weapon == KICKED_WEAPON && - ((obj->oclass == GOLD_CLASS && + ((obj->oclass == COIN_CLASS && OBJ_AT(bhitpos.x, bhitpos.y)) || - ship_object(obj, bhitpos.x, bhitpos.y, costly))) { + ship_object(obj, bhitpos.x, bhitpos.y, + costly_spot(bhitpos.x, bhitpos.y)))) { tmp_at(DISP_END, 0); return (struct monst *)0; } @@ -2770,12 +2779,14 @@ break; /* physical objects fall onto sink */ #endif } + /* thrown/kicked missile has moved away from its starting spot */ + point_blank = FALSE; /* affects passing through iron bars */ } if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0); if(shopdoor) - pay_for_damage("destroy"); + pay_for_damage("destroy", FALSE); return (struct monst *)0; } @@ -3146,7 +3157,7 @@ { struct obj *obj, *obj2; long i, scrquan, delquan; - const char *what; + char buf1[BUFSZ], buf2[BUFSZ]; int cnt = 0; for (obj = level.objects[x][y]; obj; obj = obj2) { @@ -3161,8 +3172,15 @@ if (!rn2(3)) delquan++; if (delquan) { /* save name before potential delobj() */ - what = !give_feedback ? 0 : (x == u.ux && y == u.uy) ? - xname(obj) : distant_name(obj, xname); + if (give_feedback) { + obj->quan = 1; + Strcpy(buf1, (x == u.ux && y == u.uy) ? + xname(obj) : distant_name(obj, xname)); + obj->quan = 2; + Strcpy(buf2, (x == u.ux && y == u.uy) ? + xname(obj) : distant_name(obj, xname)); + obj->quan = scrquan; + } /* useupf(), which charges, only if hero caused damage */ if (u_caused) useupf(obj, delquan); else if (delquan < scrquan) obj->quan -= delquan; @@ -3170,9 +3188,9 @@ cnt += delquan; if (give_feedback) { if (delquan > 1) - pline("%ld %s burn.", delquan, what); + pline("%ld %s burn.", delquan, buf2); else - pline("%s burns.", An(what)); + pline("%s burns.", An(buf1)); } } } @@ -3424,10 +3442,12 @@ dy = -dy; } else { if(isok(sx,lsy) && ZAP_POS(rmn = levl[sx][lsy].typ) && + !closed_door(sx,lsy) && (IS_ROOM(rmn) || (isok(sx+dx,lsy) && ZAP_POS(levl[sx+dx][lsy].typ)))) bounce = 1; if(isok(lsx,sy) && ZAP_POS(rmn = levl[lsx][sy].typ) && + !closed_door(lsx,sy) && (IS_ROOM(rmn) || (isok(lsx,sy+dy) && ZAP_POS(levl[lsx][sy+dy].typ)))) if(!bounce || rn2(2)) @@ -3448,7 +3468,7 @@ if (shopdamage) pay_for_damage(abstype == ZT_FIRE ? "burn away" : abstype == ZT_COLD ? "shatter" : - abstype == ZT_DEATH ? "disintegrate" : "destroy"); + abstype == ZT_DEATH ? "disintegrate" : "destroy", FALSE); bhitpos = save_bhitpos; } #endif /*OVLB*/ @@ -3708,12 +3728,14 @@ obj->onamelth = 0; /* no names */ obj->oxlth = 0; /* no extra data */ obj->oattached = OATTACHED_NOTHING; - obj_extract_self(obj); /* move rocks back on top */ - place_object(obj, obj->ox, obj->oy); - if(!does_block(obj->ox,obj->oy,&levl[obj->ox][obj->oy])) - unblock_point(obj->ox,obj->oy); - if(cansee(obj->ox,obj->oy)) - newsym(obj->ox,obj->oy); + if (obj->where == OBJ_FLOOR) { + obj_extract_self(obj); /* move rocks back on top */ + place_object(obj, obj->ox, obj->oy); + if(!does_block(obj->ox,obj->oy,&levl[obj->ox][obj->oy])) + unblock_point(obj->ox,obj->oy); + if(cansee(obj->ox,obj->oy)) + newsym(obj->ox,obj->oy); + } } /* handle statue hit by striking/force bolt/pick-axe */ @@ -3742,7 +3764,7 @@ return TRUE; } -const char *destroy_strings[] = { +const char * const destroy_strings[] = { /* also used in trap.c */ "freezes and shatters", "freeze and shatter", "shattered potion", "boils and explodes", "boil and explode", "boiling potion", "catches fire and burns", "catch fire and burn", "burning scroll", @@ -3765,6 +3787,7 @@ obj2 = obj->nobj; if(obj->oclass != osym) continue; /* test only objs of type osym */ if(obj->oartifact) continue; /* don't destroy artifacts */ + if(obj->in_use && obj->quan == 1) continue; /* not available */ xresist = skip = 0; #ifdef GCC_WARN dmg = dindx = 0; @@ -3836,6 +3859,7 @@ break; } if(!skip) { + if (obj->in_use) --quan; /* one will be used up elsewhere */ for(i = cnt = 0L; i < quan; i++) if(!rn2(3)) cnt++; @@ -3987,11 +4011,12 @@ /* attack level */ switch (oclass) { case WAND_CLASS: alev = 12; break; - case TOOL_CLASS: alev = 10; break; + case TOOL_CLASS: alev = 10; break; /* instrument */ + case WEAPON_CLASS: alev = 10; break; /* artifact */ case SCROLL_CLASS: alev = 9; break; case POTION_CLASS: alev = 6; break; case RING_CLASS: alev = 5; break; - default: alev = u.ulevel; break; /* spell */ + default: alev = u.ulevel; break; /* spell */ } /* defense level */ dlev = (int)mtmp->m_lev; @@ -4052,33 +4077,19 @@ u.uconduct.wishes++; if (otmp != &zeroobj) { - /* place_object looses these */ - boolean crysknife = (otmp->otyp == CRYSKNIFE); - int oerode = otmp->oerodeproof; - - /* in case touching this object turns out to be fatal */ - place_object(otmp, u.ux, u.uy); - - if (otmp->oartifact && !touch_artifact(otmp,&youmonst)) { - obj_extract_self(otmp); /* remove it from the floor */ - dropy(otmp); /* now put it back again :-) */ - } else { - obj_extract_self(otmp); - if (crysknife) { - otmp->otyp = CRYSKNIFE; - otmp->oerodeproof = oerode; - } - /* The(aobjnam()) is safe since otmp is unidentified -dlc */ - (void) hold_another_object(otmp, u.uswallow ? + /* The(aobjnam()) is safe since otmp is unidentified -dlc */ + (void) hold_another_object(otmp, u.uswallow ? "Oops! %s out of your reach!" : - Is_airlevel(&u.uz) || u.uinwater ? + (Is_airlevel(&u.uz) || + Is_waterlevel(&u.uz) || + levl[u.ux][u.uy].typ < IRONBARS || + levl[u.ux][u.uy].typ >= ICE) ? "Oops! %s away from you!" : "Oops! %s to the floor!", The(aobjnam(otmp, Is_airlevel(&u.uz) || u.uinwater ? "slip" : "drop")), (const char *)0); - } u.ublesscnt += rn1(100,50); /* the gods take notice */ } }