diff -Naurd ../nethack-3.4.1/include/config1.h ./include/config1.h --- ../nethack-3.4.1/include/config1.h Sun Feb 23 14:43:19 2003 +++ ./include/config1.h Mon Sep 1 14:33:32 2003 @@ -130,6 +130,11 @@ #endif +#if defined(__linux__) && defined(__GNUC__) && !defined(_GNU_SOURCE) +/* ensure _GNU_SOURCE is defined before including any system headers */ +# define _GNU_SOURCE +#endif + #ifdef VMS /* really old compilers need special handling, detected here */ # undef UNIX # ifdef __DECC diff -Naurd ../nethack-3.4.1/include/decl.h ./include/decl.h --- ../nethack-3.4.1/include/decl.h Sun Feb 23 14:43:19 2003 +++ ./include/decl.h Mon Sep 1 14:33:32 2003 @@ -222,8 +222,8 @@ #include "spell.h" E NEARDATA struct spell spl_book[]; /* sized in decl.c */ -#ifdef TEXTCOLOR #include "color.h" +#ifdef TEXTCOLOR E const int zapcolors[]; #endif diff -Naurd ../nethack-3.4.1/include/display.h ./include/display.h --- ../nethack-3.4.1/include/display.h Sun Feb 23 14:43:20 2003 +++ ./include/display.h Mon Sep 1 14:33:32 2003 @@ -133,8 +133,7 @@ * 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) +#define senseself() (canseeself() || Unblind_telepat || Detect_monsters) /* * random_monster() diff -Naurd ../nethack-3.4.1/include/extern.h ./include/extern.h --- ../nethack-3.4.1/include/extern.h Sun Feb 23 14:43:20 2003 +++ ./include/extern.h Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)extern.h 3.4 2003/01/02 */ +/* SCCS Id: @(#)extern.h 3.4 2003/03/10 */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -178,6 +178,7 @@ #ifdef WIZARD E void NDECL(sanity_check); #endif +E char FDECL(yn_function, (const char *, const char *, CHAR_P)); /* ### dbridge.c ### */ @@ -339,6 +340,7 @@ E char *FDECL(distant_monnam, (struct monst *,int,char *)); E const char *NDECL(rndmonnam); E const char *FDECL(hcolor, (const char *)); +E const char *NDECL(rndcolor); #ifdef REINCARNATION E const char *NDECL(roguename); #endif @@ -385,6 +387,7 @@ 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 struct obj *NDECL(unchanger); E void NDECL(reset_remarm); E int NDECL(doddoremarm); E int FDECL(destroy_arm, (struct obj *)); @@ -418,6 +421,7 @@ /* ### dokick.c ### */ E boolean FDECL(ghitm, (struct monst *,struct obj *)); +E void FDECL(container_impact_dmg, (struct obj *)); E int NDECL(dokick); E boolean FDECL(ship_object, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P)); E void NDECL(obj_delivery); @@ -498,7 +502,7 @@ E xchar NDECL(level_difficulty); E schar FDECL(lev_by_name, (const char *)); #ifdef WIZARD -E void NDECL(print_dungeon); +E schar FDECL(print_dungeon, (BOOLEAN_P)); #endif /* ### eat.c ### */ @@ -758,6 +762,7 @@ (struct obj *,const char *,const char *,const char *)); E void FDECL(useupall, (struct obj *)); E void FDECL(useup, (struct obj *)); +E void FDECL(consume_obj_charge, (struct obj *,BOOLEAN_P)); E void FDECL(freeinv_core, (struct obj *)); E void FDECL(freeinv, (struct obj *)); E void FDECL(delallobj, (int,int)); @@ -789,6 +794,7 @@ E const char *FDECL(dfeature_at, (int,int,char *)); E int FDECL(look_here, (int,BOOLEAN_P)); E int NDECL(dolook); +E boolean FDECL(will_feel_cockatrice, (struct obj *,BOOLEAN_P)); E void FDECL(feel_cockatrice, (struct obj *,BOOLEAN_P)); E void FDECL(stackobj, (struct obj *)); E int NDECL(doprgold); @@ -868,6 +874,7 @@ E int FDECL(macread, (int,void *,unsigned)); E int FDECL(macwrite, (int,void *,unsigned)); E long FDECL(macseek, (int,long,short)); +E int FDECL(macunlink, (const char *)); /* ### macsnd.c ### */ @@ -927,6 +934,7 @@ #ifdef GOLDOBJ E void FDECL(mkmonmoney, (struct monst *, long)); #endif +E void FDECL(bagotricks, (struct obj *)); /* ### mapglyph.c ### */ @@ -1002,6 +1010,7 @@ /* ### mkmap.c ### */ void FDECL(flood_fill_rm, (int,int,int,BOOLEAN_P,BOOLEAN_P)); +void FDECL(remove_rooms, (int,int,int,int)); /* ### mkmaze.c ### */ @@ -1086,6 +1095,7 @@ /* ### mon.c ### */ E int FDECL(undead_to_corpse, (int)); +E int FDECL(genus, (int,int)); E int FDECL(pm_to_cham, (int)); E int FDECL(minliquid, (struct monst *)); E int NDECL(movemon); @@ -1312,6 +1322,7 @@ E void NDECL(nttty_rubout); E int NDECL(tgetch); E int FDECL(ntposkey,(int *, int *, int *)); +E void FDECL(set_output_mode, (int)); #endif /* ### o_init.c ### */ @@ -1343,6 +1354,7 @@ E boolean FDECL(not_fully_identified, (struct obj *)); E char *FDECL(corpse_xname, (struct obj *,BOOLEAN_P)); E char *FDECL(cxname, (struct obj *)); +E char *FDECL(killer_xname, (struct obj *)); E const char *FDECL(singular, (struct obj *,char *(*)(OBJ_P))); E char *FDECL(an, (const char *)); E char *FDECL(An, (const char *)); @@ -1355,6 +1367,8 @@ E char *FDECL(Doname2, (struct obj *)); E char *FDECL(yname, (struct obj *)); E char *FDECL(Yname2, (struct obj *)); +E char *FDECL(ysimple_name, (struct obj *)); +E char *FDECL(Ysimple_name2, (struct obj *)); E char *FDECL(makeplural, (const char *)); E char *FDECL(makesingular, (const char *)); E struct obj *FDECL(readobjnam, (char *,struct obj *,BOOLEAN_P)); @@ -1379,6 +1393,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_wc2_option_mod_status, (unsigned long, int)); E void FDECL(set_option_mod_status, (const char *,int)); /* ### pager.c ### */ @@ -1469,6 +1484,8 @@ E int NDECL(doloot); E int FDECL(use_container, (struct obj *,int)); E int FDECL(loot_mon, (struct monst *,int *,boolean *)); +E const char *FDECL(safe_qbuf, (const char *,unsigned, + const char *,const char *,const char *)); /* ### pline.c ### */ @@ -2046,6 +2063,9 @@ #ifdef UNIX E void NDECL(getlock); E void FDECL(regularize, (char *)); +# if defined(TIMED_DELAY) && !defined(msleep) && defined(SYSV) +E void FDECL(msleep, (unsigned)); +# endif # ifdef SHELL E int NDECL(dosh); # endif /* SHELL */ diff -Naurd ../nethack-3.4.1/include/flag.h ./include/flag.h --- ../nethack-3.4.1/include/flag.h Sun Feb 23 14:43:20 2003 +++ ./include/flag.h Mon Sep 1 14:33:32 2003 @@ -167,10 +167,12 @@ 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 */ + uchar num_pad_mode; 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 */ - uchar bouldersym; /* symbol for boulder display */ + uchar bouldersym; /* symbol for boulder display */ + coord travelcc; /* coordinates for travel_cache */ #ifdef WIZARD boolean sanity_check; /* run sanity checks */ boolean mon_polycontrol; /* debug: control monster polymorphs */ @@ -186,6 +188,8 @@ #endif #ifdef MICRO boolean BIOS; /* use IBM or ST BIOS calls when appropriate */ +#endif +#if defined(MICRO) || defined(WIN32) boolean rawio; /* whether can use rawio (IOCTL call) */ #endif #ifdef MAC_GRAPHICS_ENV @@ -254,6 +258,9 @@ in the message window */ boolean wc_eight_bit_input; /* allow eight bit input */ boolean wc_mouse_support; /* allow mouse support */ + boolean wc2_fullscreen; /* run fullscreen */ + boolean wc2_softkeyboard; /* use software keyboard */ + boolean wc2_wraptext; /* wrap text */ boolean cmdassist; /* provide detailed assistance for some commands */ boolean obsolete; /* obsolete options can point at this, it isn't used */ diff -Naurd ../nethack-3.4.1/include/global.h ./include/global.h --- ../nethack-3.4.1/include/global.h Sun Feb 23 14:43:20 2003 +++ ./include/global.h Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)global.h 3.4 2003/02/19 */ +/* SCCS Id: @(#)global.h 3.4 2003/08/21 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ diff -Naurd ../nethack-3.4.1/include/hack.h ./include/hack.h --- ../nethack-3.4.1/include/hack.h Sun Feb 23 14:43:20 2003 +++ ./include/hack.h Mon Sep 1 14:33:32 2003 @@ -140,6 +140,7 @@ #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 */ +#define MM_ADJACENTOK 0x100 /* it is acceptable to use adjacent coordinates */ /* flags for special ggetobj status returns */ #define ALL_FINISHED 0x01 /* called routine already finished the job */ @@ -150,6 +151,7 @@ #define USE_INVLET 0x4 /* use object's invlet */ #define INVORDER_SORT 0x8 /* sort objects by packorder */ #define SIGNAL_NOMENU 0x10 /* return -1 rather than 0 if none allowed */ +#define FEEL_COCKATRICE 0x20 /* engage cockatrice checks and react */ /* Flags to control query_category() */ /* BY_NEXTHERE used by query_category() too, so skip 0x01 */ @@ -178,6 +180,8 @@ /* Flags to control dotrap() in trap.c */ #define NOWEBMSG 0x01 /* suppress stumble into web message */ +#define FORCEBUNGLE 0x02 /* adjustments appropriate for bungling */ +#define RECURSIVETRAP 0x04 /* trap changed into another type this same turn */ /* Flags to control test_move in hack.c */ #define DO_MOVE 0 /* really doing the move */ @@ -203,6 +207,7 @@ /* Macros for launching objects */ #define ROLL 0x01 /* the object is rolling */ #define FLING 0x02 /* the object is flying thru the air */ +#define LAUNCH_UNSEEN 0x40 /* hero neither caused nor saw it */ #define LAUNCH_KNOWN 0x80 /* the hero caused this by explicit action */ /* Macros for explosion types */ diff -Naurd ../nethack-3.4.1/include/obj.h ./include/obj.h --- ../nethack-3.4.1/include/obj.h Sun Feb 23 14:43:21 2003 +++ ./include/obj.h Mon Sep 1 14:33:32 2003 @@ -33,7 +33,11 @@ marks your eggs, spinach tins royal coffers for a court ( == 2) tells which fruit a fruit is - special for uball and amulet %% BAH */ + special for uball and amulet + historic and gender for statues */ +#define STATUE_HISTORIC 0x01 +#define STATUE_MALE 0x02 +#define STATUE_FEMALE 0x04 char oclass; /* object class */ char invlet; /* designation in inventory */ char oartifact; /* artifact array index */ @@ -260,6 +264,22 @@ otmp->otyp == WAX_CANDLE) #define MAX_OIL_IN_FLASK 400 /* maximum amount of oil in a potion of oil */ +/* MAGIC_LAMP intentionally excluded below */ +/* age field of this is relative age rather than absolute */ +#define age_is_relative(otmp) ((otmp)->otyp == BRASS_LANTERN\ + || (otmp)->otyp == OIL_LAMP\ + || (otmp)->otyp == CANDELABRUM_OF_INVOCATION\ + || (otmp)->otyp == TALLOW_CANDLE\ + || (otmp)->otyp == WAX_CANDLE\ + || (otmp)->otyp == POT_OIL) +/* object can be ignited */ +#define ignitable(otmp) ((otmp)->otyp == BRASS_LANTERN\ + || (otmp)->otyp == OIL_LAMP\ + || (otmp)->otyp == CANDELABRUM_OF_INVOCATION\ + || (otmp)->otyp == TALLOW_CANDLE\ + || (otmp)->otyp == WAX_CANDLE\ + || (otmp)->otyp == POT_OIL) + /* special stones */ #define is_graystone(obj) ((obj)->otyp == LUCKSTONE || \ (obj)->otyp == LOADSTONE || \ diff -Naurd ../nethack-3.4.1/include/objclass.h ./include/objclass.h --- ../nethack-3.4.1/include/objclass.h Sun Feb 23 14:43:21 2003 +++ ./include/objclass.h Mon Sep 1 14:33:32 2003 @@ -75,7 +75,7 @@ #define is_corrodeable(otmp) (objects[otmp->otyp].oc_material == COPPER || objects[otmp->otyp].oc_material == IRON) #define is_damageable(otmp) (is_rustprone(otmp) || is_flammable(otmp) || \ - is_rottable || is_corrodeable(otmp)) + is_rottable(otmp) || is_corrodeable(otmp)) schar oc_subtyp; #define oc_skill oc_subtyp /* Skills of weapons, spellbooks, tools, gems */ diff -Naurd ../nethack-3.4.1/include/patchlevel.h ./include/patchlevel.h --- ../nethack-3.4.1/include/patchlevel.h Sun Feb 23 14:43:21 2003 +++ ./include/patchlevel.h Mon Sep 1 14:33:32 2003 @@ -1,14 +1,14 @@ -/* SCCS Id: @(#)patchlevel.h 3.4 2003/02/19 */ +/* SCCS Id: @(#)patchlevel.h 3.4 2003/08/21 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ -/* NetHack 3.4.1 */ +/* NetHack 3.4.2 */ #define VERSION_MAJOR 3 #define VERSION_MINOR 4 /* * PATCHLEVEL is updated for each release. */ -#define PATCHLEVEL 1 +#define PATCHLEVEL 2 /* * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. @@ -34,12 +34,24 @@ * PP = patch level, ee = edit level, L = literal suffix "L", * with all four numbers specified as two hexadecimal digits. */ -#define VERSION_COMPATIBILITY 0x03040000L +#define VERSION_COMPATIBILITY 0x03040100L #endif /*****************************************************************************/ /* Version 3.4.x */ +/* Patch 2, August 30, 2003 + * Fix a fatal bug that caused a crash when applying figurine, candle, or + * bell that gets used up + * Fix a fatal bug that triggered a panic when your secondary weapon was + * cursed during bones file creation + * Several dozen general bug fixes + * Fixed some Gnome compilation problems on Redhat 7.2 and 8.0 + * Fixed a problem in the util Makefile + * Use random() by default under linux instead of lrand48() + * win32 tty adjustments and support for loading alternative key handlers + */ + /* Patch 1, February 22, 2003 * Fix a few fatal errors including one for reentering shops, one * involving land mines and boulders/statues, one for delayed diff -Naurd ../nethack-3.4.1/include/system.h ./include/system.h --- ../nethack-3.4.1/include/system.h Sun Feb 23 14:43:22 2003 +++ ./include/system.h Mon Sep 1 14:33:32 2003 @@ -79,7 +79,7 @@ # if !defined(__SC__) && !defined(LINUX) E long NDECL(random); # endif -# if !defined(SUNOS4) || defined(RANDOM) +# if (!defined(SUNOS4) && !defined(bsdi) && !defined(__FreeBSD__)) || defined(RANDOM) E void FDECL(srandom, (unsigned int)); # else # if !defined(bsdi) && !defined(__FreeBSD__) @@ -521,7 +521,7 @@ # endif # endif -# if defined(ULTRIX) || defined(SYSV) || defined(MICRO) || defined(VMS) || defined(MAC) || (defined(HPUX) && defined(_POSIX_SOURCE)) +# if defined(ULTRIX) || (defined(BSD) && defined(POSIX_TYPES)) || defined(SYSV) || defined(MICRO) || defined(VMS) || defined(MAC) || (defined(HPUX) && defined(_POSIX_SOURCE)) E time_t FDECL(time, (time_t *)); # else E long FDECL(time, (time_t *)); diff -Naurd ../nethack-3.4.1/include/winprocs.h ./include/winprocs.h --- ../nethack-3.4.1/include/winprocs.h Sun Feb 23 14:43:24 2003 +++ ./include/winprocs.h Mon Sep 1 14:33:32 2003 @@ -8,6 +8,7 @@ struct window_procs { const char *name; unsigned long wincap; /* window port capability options supported */ + unsigned long wincap2; /* additional window port capability options supported */ void FDECL((*win_init_nhwindows), (int *, char **)); void NDECL((*win_player_selection)); void NDECL((*win_askname)); @@ -108,7 +109,6 @@ #define nh_poskey (*windowprocs.win_nh_poskey) #define nhbell (*windowprocs.win_nhbell) #define nh_doprev_message (*windowprocs.win_doprev_message) -#define yn_function (*windowprocs.win_yn_function) #define getlin (*windowprocs.win_getlin) #define get_ext_cmd (*windowprocs.win_get_ext_cmd) #define number_pad (*windowprocs.win_number_pad) @@ -122,6 +122,12 @@ #define get_color_string (*windowprocs.win_get_color_string) #endif +/* 3.4.2: There is a real yn_function() in the core now, which does + * some buffer length validation on the parameters prior to + * invoking the window port routine. yn_function() is in cmd.c + */ +/* #define yn_function (*windowprocs.win_yn_function) */ + /* other defs that really should go away (they're tty specific) */ #define start_screen (*windowprocs.win_start_screen) #define end_screen (*windowprocs.win_end_screen) @@ -168,6 +174,11 @@ #define WC_MOUSE_SUPPORT 0x80000000L /* 32 mouse support */ /* no free bits */ +#define WC2_FULLSCREEN 0x01L /* 01 display full screen */ +#define WC2_SOFTKEYBOARD 0x02L /* 02 software keyboard */ +#define WC2_WRAPTEXT 0x04L /* 04 wrap long lines of text */ + /* 29 free bits */ + #define ALIGN_LEFT 1 #define ALIGN_RIGHT 2 #define ALIGN_TOP 3 diff -Naurd ../nethack-3.4.1/include/wintype.h ./include/wintype.h --- ../nethack-3.4.1/include/wintype.h Sun Feb 23 14:43:24 2003 +++ ./include/wintype.h Mon Sep 1 14:33:32 2003 @@ -13,6 +13,7 @@ struct obj *a_obj; int a_int; char a_char; + schar a_schar; /* add types as needed */ } anything; #define ANY_P union any /* avoid typedef in prototypes */ diff -Naurd ../nethack-3.4.1/src/allmain.c ./src/allmain.c --- ../nethack-3.4.1/src/allmain.c Sun Feb 23 14:43:24 2003 +++ ./src/allmain.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)allmain.c 3.4 2002/01/04 */ +/* SCCS Id: @(#)allmain.c 3.4 2003/04/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -60,9 +60,6 @@ youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */ for(;;) { -#ifdef CLIPPING - cliparound(u.ux, u.uy); -#endif get_nh_event(); #ifdef POSITIONBAR do_positionbar(); @@ -381,6 +378,11 @@ sanity_check(); #endif +#ifdef CLIPPING + /* just before rhack */ + cliparound(u.ux, u.uy); +#endif + u.umoved = FALSE; if (multi > 0) { @@ -495,10 +497,11 @@ * and init_artifacts() */ init_dungeons(); /* must be before u_init() to avoid rndmonst() - * creating odd monsters for initial tins and - * eggs */ + * creating odd monsters for any tins and eggs + * in hero's initial inventory */ + init_artifacts(); /* before u_init() in case $WIZKIT specifies + * any artifacts */ u_init(); - init_artifacts(); #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); diff -Naurd ../nethack-3.4.1/src/apply.c ./src/apply.c --- ../nethack-3.4.1/src/apply.c Sun Feb 23 14:43:24 2003 +++ ./src/apply.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)apply.c 3.4 2003/02/13 */ +/* SCCS Id: @(#)apply.c 3.4 2003/05/25 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -21,13 +21,13 @@ STATIC_DCL void FDECL(use_magic_whistle, (struct obj *)); STATIC_DCL void FDECL(use_leash, (struct obj *)); STATIC_DCL int FDECL(use_mirror, (struct obj *)); -STATIC_DCL void FDECL(use_bell, (struct obj *)); +STATIC_DCL void FDECL(use_bell, (struct obj **)); STATIC_DCL void FDECL(use_candelabrum, (struct obj *)); -STATIC_DCL void FDECL(use_candle, (struct obj *)); +STATIC_DCL void FDECL(use_candle, (struct obj **)); STATIC_DCL void FDECL(use_lamp, (struct obj *)); STATIC_DCL void FDECL(light_cocktail, (struct obj *)); STATIC_DCL void FDECL(use_tinning_kit, (struct obj *)); -STATIC_DCL void FDECL(use_figurine, (struct obj *)); +STATIC_DCL void FDECL(use_figurine, (struct obj **)); STATIC_DCL void FDECL(use_grease, (struct obj *)); STATIC_DCL void FDECL(use_trap, (struct obj *)); STATIC_DCL void FDECL(use_stone, (struct obj *)); @@ -65,8 +65,8 @@ pline(nothing_happens); return (1); } - check_unpaid(obj); - obj->spe--; + consume_obj_charge(obj, TRUE); + if (obj->cursed && !rn2(2)) { (void) zapyourself(obj, TRUE); } else if (u.uswallow) { @@ -202,10 +202,13 @@ use_stethoscope(obj) register struct obj *obj; { - static long last_used = 0; + static long last_used_move = -1; + static short last_used_movement = 0; struct monst *mtmp; struct rm *lev; int rx, ry, res; + boolean interference = (u.uswallow && is_whirly(u.ustuck->data) && + !rn2(Role_if(PM_HEALER) ? 10 : 3)); if (nohands(youmonst.data)) { /* should also check for no ears and/or deaf */ You("have no hands!"); /* not `body_part(HAND)' */ @@ -216,17 +219,28 @@ } if (!getdir((char *)0)) return 0; - res = (moves + monstermoves == last_used); - last_used = moves + monstermoves; + res = (moves == last_used_move) && + (youmonst.movement == last_used_movement); + last_used_move = moves; + last_used_movement = youmonst.movement; +#ifdef STEED + if (u.usteed && u.dz > 0) { + if (interference) { + pline("%s interferes.", Monnam(u.ustuck)); + mstatusline(u.ustuck); + } else + mstatusline(u.usteed); + return res; + } else +#endif if (u.uswallow && (u.dx || u.dy || u.dz)) { mstatusline(u.ustuck); return res; -#ifdef STEED - } else if (u.usteed && u.dz > 0) { - mstatusline(u.usteed); + } else if (u.uswallow && interference) { + pline("%s interferes.", Monnam(u.ustuck)); + mstatusline(u.ustuck); return res; -#endif } else if (u.dz) { if (Underwater) You_hear("faint splashing."); @@ -725,9 +739,10 @@ } STATIC_OVL void -use_bell(obj) -register struct obj *obj; +use_bell(optr) +struct obj **optr; { + register struct obj *obj = *optr; struct monst *mtmp; boolean wakem = FALSE, learno = FALSE, ordinary = (obj->otyp != BELL_OF_OPENING || !obj->spe), @@ -762,6 +777,7 @@ if (!obj_resists(obj, 93, 100)) { pline("%s shattered!", Tobjnam(obj, "have")); useup(obj); + *optr = 0; } else switch (rn2(3)) { default: break; @@ -778,8 +794,7 @@ } else { /* charged Bell of Opening */ - check_unpaid(obj); - obj->spe--; + consume_obj_charge(obj, TRUE); if (u.uswallow) { if (!obj->cursed) @@ -893,9 +908,10 @@ } STATIC_OVL void -use_candle(obj) -register struct obj *obj; +use_candle(optr) +struct obj **optr; { + register struct obj *obj = *optr; register struct obj *otmp; const char *s = (obj->quan != 1) ? "candles" : "candle"; char qbuf[QBUFSZ]; @@ -916,7 +932,9 @@ } Sprintf(qbuf, "Attach %s", the(xname(obj))); - Sprintf(eos(qbuf), " to %s?", the(xname(otmp))); + Sprintf(eos(qbuf), " to %s?", + safe_qbuf(qbuf, sizeof(" to ?"), the(xname(otmp)), + the(simple_typename(otmp->otyp)), "it")); if(yn(qbuf) == 'n') { if (!obj->lamplit) You("try to light %s...", the(xname(obj))); @@ -925,6 +943,7 @@ } else { if ((long)otmp->spe + obj->quan > 7L) obj = splitobj(obj, 7L - (long)otmp->spe); + else *optr = 0; You("attach %ld%s %s to %s.", obj->quan, !otmp->spe ? "" : " more", s, the(xname(otmp))); @@ -1007,10 +1026,7 @@ { xchar x, y; - if (!obj->lamplit && (obj->otyp == CANDELABRUM_OF_INVOCATION || - obj->otyp == WAX_CANDLE || obj->otyp == TALLOW_CANDLE || - obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || - obj->otyp == BRASS_LANTERN || obj->otyp == POT_OIL)) { + if (!obj->lamplit && (obj->otyp == MAGIC_LAMP || ignitable(obj))) { if ((obj->otyp == MAGIC_LAMP || obj->otyp == CANDELABRUM_OF_INVOCATION) && obj->spe == 0) @@ -1398,7 +1414,8 @@ pline("That's too insubstantial to tin."); return; } - obj->spe--; + consume_obj_charge(obj, TRUE); + if ((can = mksobj(TIN, FALSE, FALSE)) != 0) { static const char you_buy_it[] = "You tin it, you bought it!"; @@ -1696,9 +1713,10 @@ } STATIC_OVL void -use_figurine(obj) -register struct obj *obj; +use_figurine(optr) +struct obj **optr; { + register struct obj *obj = *optr; xchar x, y; coord cc; @@ -1726,6 +1744,7 @@ (void) make_familiar(obj, cc.x, cc.y, FALSE); (void) stop_timer(FIG_TRANSFORM, (genericptr_t)obj); useup(obj); + *optr = 0; } static NEARDATA const char lubricables[] = { ALL_CLASSES, ALLOW_NONE, 0 }; @@ -1748,8 +1767,8 @@ if (obj->spe > 0) { if ((obj->cursed || Fumbling) && !rn2(2)) { - check_unpaid(obj); - obj->spe--; + consume_obj_charge(obj, TRUE); + pline("%s from your %s.", Tobjnam(obj, "slip"), makeplural(body_part(FINGER))); dropx(obj); @@ -1771,8 +1790,8 @@ return; } #endif - check_unpaid(obj); - obj->spe--; + consume_obj_charge(obj, TRUE); + if (otmp != &zeroobj) { You("cover %s with a thick layer of grease.", yname(otmp)); @@ -1800,12 +1819,14 @@ struct obj *tobj; xchar tx, ty; int time_needed; + boolean force_bungle; } trapinfo; void reset_trapset() { trapinfo.tobj = 0; + trapinfo.force_bungle = 0; } /* touchstones - by Ken Arnold */ @@ -2004,7 +2025,37 @@ trapinfo.time_needed += (tmp > 12) ? 1 : (tmp > 7) ? 2 : 4; /*[fumbling and/or confusion and/or cursed object check(s) should be incorporated here instead of in set_trap]*/ +#ifdef STEED + if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { + boolean chance; + if (Fumbling || otmp->cursed) chance = (rnl(10) > 3); + else chance = (rnl(10) > 5); + You("aren't very skilled at reaching from %s.", + mon_nam(u.usteed)); + Sprintf(buf, "Continue your attempt to set %s?", + the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); + if(yn(buf) == 'y') { + if (chance) { + switch(ttyp) { + case LANDMINE: /* set it off */ + trapinfo.time_needed = 0; + trapinfo.force_bungle = TRUE; + break; + case BEAR_TRAP: /* drop it without arming it */ + reset_trapset(); + You("drop %s!", + the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); + dropx(otmp); + return; + } + } + } else { + reset_trapset(); + return; + } + } +#endif You("begin setting %s %s.", shk_your(buf, otmp), defsyms[trap_to_defsym(what_trap(ttyp))].explanation); @@ -2038,9 +2089,12 @@ if (*in_rooms(u.ux,u.uy,SHOPBASE)) { add_damage(u.ux, u.uy, 0L); /* schedule removal */ } - You("finish arming %s.", - the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); - if ((otmp->cursed || Fumbling) && (rnl(10) > 5)) dotrap(ttmp, 0); + if (!trapinfo.force_bungle) + You("finish arming %s.", + the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); + if (((otmp->cursed || Fumbling) && (rnl(10) > 5)) || trapinfo.force_bungle) + dotrap(ttmp, + (unsigned)(trapinfo.force_bungle ? FORCEBUNGLE : 0)); } else { /* this shouldn't happen */ Your("trap setting attempt fails."); @@ -2344,7 +2398,9 @@ } else if (distu(cc.x, cc.y) < min_range) { pline("Too close!"); return (res); - } else if (!cansee(cc.x, cc.y)) { + } else if (!cansee(cc.x, cc.y) && + ((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0 || + !canseemon(mtmp))) { You(cant_see_spot); return (res); } @@ -2545,7 +2601,9 @@ char confirm[QBUFSZ], the_wand[BUFSZ], buf[BUFSZ]; Strcpy(the_wand, yname(obj)); - Sprintf(confirm, "Are you really sure you want to break %s?", the_wand); + Sprintf(confirm, "Are you really sure you want to break %s?", + safe_qbuf("", sizeof("Are you really sure you want to break ?"), + the_wand, ysimple_name(obj), "the wand")); if (yn(confirm) == 'n' ) return 0; if (nohands(youmonst.data)) { @@ -2712,7 +2770,7 @@ int doapply() { - register struct obj *obj; + struct obj *obj; register int res = 1; char class_list[MAXOCLASSES+2]; @@ -2765,18 +2823,7 @@ res = use_container(obj, 1); break; case BAG_OF_TRICKS: - if(obj->spe > 0) { - register int cnt = 1; - - check_unpaid(obj); - obj->spe--; - if(!rn2(23)) cnt += rn2(7) + 1; - while(cnt--) - (void) makemon((struct permonst *) 0, - u.ux, u.uy, NO_MM_FLAGS); - makeknown(BAG_OF_TRICKS); - } else - pline(nothing_happens); + bagotricks(obj); break; case CAN_OF_GREASE: use_grease(obj); @@ -2838,14 +2885,14 @@ break; case BELL: case BELL_OF_OPENING: - use_bell(obj); + use_bell(&obj); break; case CANDELABRUM_OF_INVOCATION: use_candelabrum(obj); break; case WAX_CANDLE: case TALLOW_CANDLE: - use_candle(obj); + use_candle(&obj); break; case OIL_LAMP: case MAGIC_LAMP: @@ -2882,7 +2929,7 @@ goto xit; case FIGURINE: - use_figurine(obj); + use_figurine(&obj); break; case UNICORN_HORN: use_unicorn_horn(obj); @@ -2904,8 +2951,7 @@ struct obj *otmp; const char *what; - check_unpaid(obj); - obj->spe--; + consume_obj_charge(obj, TRUE); if (!rn2(13)) { otmp = mkobj(POTION_CLASS, FALSE); if (objects[otmp->otyp].oc_magic) do { @@ -2960,7 +3006,7 @@ nomul(0); return 0; } - if (res && obj->oartifact) arti_speak(obj); + if (res && obj && obj->oartifact) arti_speak(obj); nomul(0); return res; } diff -Naurd ../nethack-3.4.1/src/artifact.c ./src/artifact.c --- ../nethack-3.4.1/src/artifact.c Sun Feb 23 14:43:24 2003 +++ ./src/artifact.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)artifact.c 3.4 2003/02/08 */ +/* SCCS Id: @(#)artifact.c 3.4 2003/08/11 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -821,6 +821,10 @@ switch (attack_indx) { case MB_INDEX_CANCEL: old_uasmon = youmonst.data; + /* No mdef->mcan check: even a cancelled monster can be polymorphed + * into a golem, and the "cancel" effect acts as if some magical + * energy remains in spellcasting defenders to be absorbed later. + */ if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) { resisted = TRUE; } else { @@ -938,7 +942,8 @@ boolean youattack = (magr == &youmonst); boolean youdefend = (mdef == &youmonst); boolean vis = (!youattack && magr && cansee(magr->mx, magr->my)) - || (!youdefend && cansee(mdef->mx, mdef->my)); + || (!youdefend && cansee(mdef->mx, mdef->my)) + || (youattack && u.uswallow && mdef == u.ustuck && !Blind); boolean realizes_damage; const char *wepdesc; static const char you[] = "you"; @@ -1194,7 +1199,8 @@ /* It's a special power, not "just" a property */ if(obj->age > monstermoves) { /* the artifact is tired :-) */ - You_feel("that %s is ignoring you.", the(xname(obj))); + You_feel("that %s %s ignoring you.", + the(xname(obj)), otense(obj, "are")); /* and just got more so; patience is essential... */ obj->age += (long) d(3,10); return 1; @@ -1352,7 +1358,8 @@ 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))); + You_feel("that %s %s ignoring you.", + the(xname(obj)), otense(obj, "are")); /* can't just keep repeatedly trying */ obj->age += (long) d(3,10); return 1; diff -Naurd ../nethack-3.4.1/src/bones.c ./src/bones.c --- ../nethack-3.4.1/src/bones.c Sun Feb 23 14:43:25 2003 +++ ./src/bones.c Mon Sep 1 14:33:32 2003 @@ -106,6 +106,7 @@ otmp->quan = (long)otmp->spe; otmp->spe = 0; otmp->owt = weight(otmp); + curse(otmp); } else if (otmp->otyp == BELL_OF_OPENING) { otmp->otyp = BELL; curse(otmp); @@ -124,6 +125,7 @@ { struct obj *otmp; + uswapwep = 0; /* ensure curse() won't cause swapwep to drop twice */ while ((otmp = invent) != 0) { obj_extract_self(otmp); obj_no_longer_held(otmp); diff -Naurd ../nethack-3.4.1/src/cmd.c ./src/cmd.c --- ../nethack-3.4.1/src/cmd.c Sun Feb 23 14:43:25 2003 +++ ./src/cmd.c Mon Sep 1 14:33:32 2003 @@ -552,7 +552,7 @@ STATIC_PTR int wiz_where() { - if (wizard) print_dungeon(); + if (wizard) (void) print_dungeon(FALSE); else pline("Unavailable command '^O'."); return 0; } @@ -1789,7 +1789,18 @@ flags.move = FALSE; return; /* probably we just had an interrupt */ } - + if (iflags.num_pad && iflags.num_pad_mode == 1) { + /* This handles very old inconsistent DOS/Windows behaviour + * in a new way: earlier, the keyboard handler mapped these, + * which caused counts to be strange when entered from the + * number pad. Now do not map them until here. + */ + switch (*cmd) { + case '5': *cmd = 'g'; break; + case M('5'): *cmd = 'G'; break; + case M('0'): *cmd = 'I'; break; + } + } /* handle most movement commands */ do_walk = do_rush = prefix_seen = FALSE; flags.travel = 0; @@ -2091,20 +2102,34 @@ 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"); + if (iflags.num_pad && u.umonnum == PM_GRID_BUG) { + putstr(win, 0, "Valid direction keys in your current form (with number_pad on) are:"); + putstr(win, 0, " 8 "); + putstr(win, 0, " | "); + putstr(win, 0, " 4- . -6"); + putstr(win, 0, " | "); + putstr(win, 0, " 2 "); + } else if (u.umonnum == PM_GRID_BUG) { + putstr(win, 0, "Valid direction keys in your current form are:"); + putstr(win, 0, " k "); + putstr(win, 0, " | "); + putstr(win, 0, " h- . -l"); + putstr(win, 0, " | "); + putstr(win, 0, " j "); + } else 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, "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"); @@ -2322,7 +2347,7 @@ { exit_nhwindows("End of input?"); #ifndef NOSAVEONHANGUP - if (!program_state.done_hup++) + if (!program_state.done_hup++ && program_state.something_worth_saving) (void) dosave0(); #endif clearlocks(); @@ -2384,15 +2409,20 @@ if (!iflags.travelcmd) return 0; cmd[1]=0; - cc.x = u.ux; - cc.y = u.uy; + cc.x = iflags.travelcc.x; + cc.y = iflags.travelcc.y; + if (cc.x == -1 && cc.y == -1) { + /* No cached destination, start attempt from current position */ + cc.x = u.ux; + cc.y = u.uy; + } pline("Where do you want to travel to?"); if (getpos(&cc, TRUE, "the desired destination") < 0) { /* user pressed ESC */ return 0; } - u.tx = cc.x; - u.ty = cc.y; + iflags.travelcc.x = u.tx = cc.x; + iflags.travelcc.y = u.ty = cc.y; cmd[0] = CMD_TRAVEL; readchar_queue = cmd; return 0; @@ -2447,5 +2479,31 @@ # endif /*PORT_DEBUG*/ #endif /* OVL0 */ +#ifdef OVLB +/* + * Parameter validator for generic yes/no function to prevent + * the core from sending too long a prompt string to the + * window port causing a buffer overflow there. + */ +char +yn_function(query,resp, def) +const char *query,*resp; +char def; +{ + char qbuf[QBUFSZ]; + unsigned truncspot, reduction = sizeof(" [N] ?") + 1; + + if (resp) reduction += strlen(resp) + sizeof(" () "); + if (strlen(query) < (QBUFSZ - reduction)) + return (*windowprocs.win_yn_function)(query, resp, def); + paniclog("Query truncated: ", query); + reduction += sizeof("..."); + truncspot = QBUFSZ - reduction; + (void) strncpy(qbuf, query, (int)truncspot); + qbuf[truncspot] = '\0'; + Strcat(qbuf,"..."); + return (*windowprocs.win_yn_function)(qbuf, resp, def); +} +#endif /*cmd.c*/ diff -Naurd ../nethack-3.4.1/src/detect.c ./src/detect.c --- ../nethack-3.4.1/src/detect.c Sun Feb 23 14:43:25 2003 +++ ./src/detect.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)detect.c 3.4 1999/12/06 */ +/* SCCS Id: @(#)detect.c 3.4 2003/08/13 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -797,11 +797,11 @@ break; case 5 : pline("%s!", Tobjnam(obj, "explode")); useup(obj); + obj = 0; /* it's gone */ losehp(rnd(30), "exploding crystal ball", KILLED_BY_AN); break; } - check_unpaid(obj); - obj->spe--; + if (obj) consume_obj_charge(obj, TRUE); return; } @@ -825,8 +825,7 @@ default: pline("Oh wow... like a kaleidoscope!"); break; } - check_unpaid(obj); - obj->spe--; + consume_obj_charge(obj, TRUE); } return; } @@ -848,8 +847,7 @@ int ret = 0; makeknown(CRYSTAL_BALL); - check_unpaid(obj); - obj->spe--; + consume_obj_charge(obj, TRUE); if ((class = def_char_to_objclass(ch)) != MAXOCLASSES) ret = object_detect((struct obj *)0, class); diff -Naurd ../nethack-3.4.1/src/dig.c ./src/dig.c --- ../nethack-3.4.1/src/dig.c Sun Feb 23 14:43:25 2003 +++ ./src/dig.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)dig.c 3.4 2003/01/29 */ +/* SCCS Id: @(#)dig.c 3.4 2003/03/23 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -492,6 +492,8 @@ boolean at_u = (x == u.ux) && (y == u.uy); boolean wont_fall = Levitation || Flying; + if (u.utrap && u.utraptype == TT_INFLOOR) u.utrap = 0; + /* these furniture checks were in dighole(), but wand breaking bypasses that routine and calls us directly */ if (IS_FOUNTAIN(lev->typ)) { @@ -546,11 +548,12 @@ if(at_u) { if (!wont_fall) { + if (!Passes_walls) u.utrap = rn1(4,2); - u.utraptype = TT_PIT; - vision_full_recalc = 1; /* vision limits change */ + u.utraptype = TT_PIT; + vision_full_recalc = 1; /* vision limits change */ } else - u.utrap = 0; + u.utrap = 0; if (oldobjs != newobjs) /* something unearthed */ (void) pickup(1); /* detects pit */ } else if(mtmp) { @@ -1182,7 +1185,7 @@ (void)xname(otmp); /* set dknown, maybe bknown */ stackobj(otmp); } - if (Invisible) newsym(u.ux, u.uy); + newsym(u.ux, u.uy); } else { watch_dig((struct monst *)0, u.ux, u.uy, TRUE); (void) dighole(FALSE); diff -Naurd ../nethack-3.4.1/src/display.c ./src/display.c --- ../nethack-3.4.1/src/display.c Sun Feb 23 14:43:25 2003 +++ ./src/display.c Mon Sep 1 14:33:32 2003 @@ -272,9 +272,11 @@ map_invisible(x, y) register xchar x, y; { - if (level.flags.hero_memory) - levl[x][y].glyph = GLYPH_INVISIBLE; - show_glyph(x, y, GLYPH_INVISIBLE); + if (x != u.ux || y != u.uy) { /* don't display I at hero's location */ + if (level.flags.hero_memory) + levl[x][y].glyph = GLYPH_INVISIBLE; + show_glyph(x, y, GLYPH_INVISIBLE); + } } /* diff -Naurd ../nethack-3.4.1/src/do.c ./src/do.c --- ../nethack-3.4.1/src/do.c Sun Feb 23 14:43:25 2003 +++ ./src/do.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)do.c 3.4 2002/09/08 */ +/* SCCS Id: @(#)do.c 3.4 2003/04/25 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -801,7 +801,7 @@ trap->ttyp == HOLE ? "down the hole" : "through the trap door"); if (trap && Is_stronghold(&u.uz)) { - goto_hell(TRUE, TRUE); + goto_hell(FALSE, TRUE); } else { at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); next_level(!trap); diff -Naurd ../nethack-3.4.1/src/do_name.c ./src/do_name.c --- ../nethack-3.4.1/src/do_name.c Sun Feb 23 14:43:26 2003 +++ ./src/do_name.c Mon Sep 1 14:33:32 2003 @@ -1002,6 +1002,15 @@ hcolors[rn2(SIZE(hcolors))] : colorpref; } +/* return a random real color unless hallucinating */ +const char * +rndcolor() +{ + int k = rn2(CLR_MAX); + return Hallucination ? hcolor((char *)0) : (k == NO_COLOR) ? + "colorless" : c_obj_colors[k]; +} + /* Aliases for road-runner nemesis */ static const char * const coynames[] = { diff -Naurd ../nethack-3.4.1/src/do_wear.c ./src/do_wear.c --- ../nethack-3.4.1/src/do_wear.c Sun Feb 23 14:43:26 2003 +++ ./src/do_wear.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)do_wear.c 3.4 2003/01/08 */ +/* SCCS Id: @(#)do_wear.c 3.4 2003/05/25 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,7 +10,8 @@ #else /* OVLB */ -STATIC_OVL NEARDATA long takeoff_mask = 0L, taking_off = 0L; +STATIC_OVL NEARDATA long takeoff_mask = 0L; +static NEARDATA long taking_off = 0L; static NEARDATA int todelay; static boolean cancelled_don = FALSE; @@ -431,6 +432,7 @@ } setworn((struct obj *)0, W_ARMG); cancelled_don = FALSE; + (void) encumber_msg(); /* immediate feedback for GoP */ /* Prevent wielding cockatrice when not wearing gloves */ if (uwep && uwep->otyp == CORPSE && @@ -993,8 +995,9 @@ uskin->otyp >= GRAY_DRAGON_SCALES ? "dragon scales are" : "dragon scale mail is"); else - pline("Not wearing any armor.%s", iflags.cmdassist ? - " Use 'R' command to remove accessories." : ""); + pline("Not wearing any armor.%s", (iflags.cmdassist && + (uleft || uright || uamul || ublindf)) ? + " Use 'R' command to remove accessories." : ""); return 0; } if (armorpieces > 1) @@ -1038,8 +1041,13 @@ MOREACC(ublindf); if(!Accessories) { - pline("Not wearing any accessories.%s", iflags.cmdassist ? - " Use 'T' command to take off non-accessories." : ""); + pline("Not wearing any accessories.%s", (iflags.cmdassist && + (uarm || uarmc || +#ifdef TOURIST + uarmu || +#endif + uarms || uarmh || uarmg || uarmf)) ? + " Use 'T' command to take off armor." : ""); return(0); } if (Accessories != 1) otmp = getobj(accessories, "remove"); @@ -1447,6 +1455,8 @@ You("cannot free your weapon hand to put on the ring."); return(0); } + if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) + return 1; /* costs a turn even though it didn't get worn */ setworn(otmp, mask); Ring_on(otmp); } else if (otmp->oclass == AMULET_CLASS) { @@ -1454,6 +1464,8 @@ already_wearing("an amulet"); return(0); } + if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) + return 1; setworn(otmp, W_AMUL); if (otmp->otyp == AMULET_OF_CHANGE) { Amulet_on(); @@ -1484,6 +1496,8 @@ You_cant("wear that!"); return(0); } + if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) + return 1; Blindf_on(otmp); return(1); } @@ -1651,6 +1665,14 @@ return (struct obj *)0; } +/* also for praying; find worn item that confers "Unchanging" attribute */ +struct obj * +unchanger() +{ + if (uamul && uamul->otyp == AMULET_OF_UNCHANGING) return uamul; + return 0; +} + STATIC_PTR int select_off(otmp) diff -Naurd ../nethack-3.4.1/src/dogmove.c ./src/dogmove.c --- ../nethack-3.4.1/src/dogmove.c Sun Feb 23 14:43:26 2003 +++ ./src/dogmove.c Mon Sep 1 14:33:32 2003 @@ -157,8 +157,10 @@ /* TODO: Reveal presence of sea monster (especially sharks) */ } else /* hack: observe the action if either new or old location is in view */ + /* However, invisible monsters should still be "it" even though out of + sight locations should not. */ if (cansee(x, y) || cansee(mtmp->mx, mtmp->my)) - pline("%s %s %s.", noit_Monnam(mtmp), + pline("%s %s %s.", mon_visible(mtmp) ? noit_Monnam(mtmp) : "It", devour ? "devours" : "eats", (obj->oclass == FOOD_CLASS) ? singular(obj, doname) : doname(obj)); diff -Naurd ../nethack-3.4.1/src/dokick.c ./src/dokick.c --- ../nethack-3.4.1/src/dokick.c Sun Feb 23 14:43:26 2003 +++ ./src/dokick.c Mon Sep 1 14:33:32 2003 @@ -329,16 +329,75 @@ return(0); } +/* container is kicked, dropped, thrown or otherwise impacted by player. + * Assumes container is on floor. Checks contents for possible damage. */ +void +container_impact_dmg(obj) +struct obj *obj; +{ + struct monst *shkp; + struct obj *otmp, *otmp2; + long loss = 0L; + boolean costly, insider; + xchar x = obj->ox, y = obj->oy; + + /* only consider normal containers */ + if (!Is_container(obj) || Is_mbag(obj)) return; + + costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) && + costly_spot(x, y)); + insider = (*u.ushops && inside_shop(u.ux, u.uy) && + *in_rooms(x, y, SHOPBASE) == *u.ushops); + + for (otmp = obj->cobj; otmp; otmp = otmp2) { + const char *result = (char *)0; + + otmp2 = otmp->nobj; + if (objects[otmp->otyp].oc_material == GLASS && + otmp->oclass != GEM_CLASS && !obj_resists(otmp, 33, 100)) { + result = "shatter"; + } else if (otmp->otyp == EGG && !rn2(3)) { + result = "cracking"; + } + if (result) { + if (otmp->otyp == MIRROR) change_luck(-2); + + /* eggs laid by you. penalty is -1 per egg, max 5, + * but it's always exactly 1 that breaks */ + if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM) + change_luck(-1); + You_hear("a muffled %s.", result); + if (costly) + loss += stolen_value(otmp, x, y, + (boolean)shkp->mpeaceful, TRUE); + if (otmp->quan > 1L) + useup(otmp); + else { + obj_extract_self(otmp); + obfree(otmp, (struct obj *) 0); + } + } + } + if (costly && loss) { + if (!insider) { + You("caused %ld %s worth of damage!", loss, currency(loss)); + make_angry_shk(shkp, x, y); + } else { + You("owe %s %ld %s for objects destroyed.", + mon_nam(shkp), loss, currency(loss)); + } + } +} + STATIC_OVL int kick_object(x, y) xchar x, y; { int range; register struct monst *mon, *shkp; - register struct obj *otmp; struct trap *trap; char bhitroom; - boolean costly, insider, isgold, slide = FALSE; + boolean costly, isgold, slide = FALSE; /* if a pile, the "top" object gets kicked */ kickobj = level.objects[x][y]; @@ -404,8 +463,6 @@ costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) && 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)) { @@ -441,51 +498,10 @@ /* a box gets a chance of breaking open here */ if(Is_box(kickobj)) { boolean otrp = kickobj->otrapped; - struct obj *otmp2; - long loss = 0L; if(range < 2) pline("THUD!"); - for(otmp = kickobj->cobj; otmp; otmp = otmp2) { - const char *result = (char *)0; - - otmp2 = otmp->nobj; - if (objects[otmp->otyp].oc_material == GLASS - && otmp->oclass != GEM_CLASS - && !obj_resists(otmp, 33, 100)) { - result = "shatter"; - } else if (otmp->otyp == EGG && !rn2(3)) { - result = "cracking"; - } - if (result) { - if (otmp->otyp == MIRROR) - change_luck(-2); - /* eggs laid by you */ - /* penalty is -1 per egg, max 5, but it's always - exactly 1 that breaks */ - if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM) - change_luck(-1); - You_hear("a muffled %s.",result); - if(costly) loss += stolen_value(otmp, x, y, - (boolean)shkp->mpeaceful, TRUE); - if (otmp->quan > 1L) - useup(otmp); - else { - obj_extract_self(otmp); - obfree(otmp, (struct obj *) 0); - } - } - } - if(costly && loss) { - if(!insider) { - You("caused %ld %s worth of damage!", - loss, currency(loss)); - make_angry_shk(shkp, x, y); - } else { - You("owe %s %ld %s for objects destroyed.", - mon_nam(shkp), loss, currency(loss)); - } - } + container_impact_dmg(kickobj); if (kickobj->olocked) { if (!rn2(5) || (martial() && !rn2(2))) { @@ -862,7 +878,7 @@ exercise(A_DEX, TRUE); return(1); } - if(IS_GRAVE(maploc->typ)) + if(IS_GRAVE(maploc->typ) || maploc->typ == IRONBARS) goto ouch; if(IS_TREE(maploc->typ)) { struct obj *treefruit; @@ -875,16 +891,21 @@ if (rn2(15) && !(maploc->looted & TREE_LOOTED) && (treefruit = rnd_treefruit_at(x, y))) { long nfruit = 8L-rnl(7), nfall; + short frtype = treefruit->otyp; 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))); nfall = scatter(x,y,2,MAY_HIT,treefruit); - if ( nfall != nfruit ) { - /* scatter left some in the tree */ + if (nfall != nfruit) { + /* scatter left some in the tree, but treefruit + * may not refer to the correct object */ + treefruit = mksobj(frtype, TRUE, FALSE); + treefruit->quan = nfruit-nfall; pline("%ld %s got caught in the branches.", nfruit-nfall, xname(treefruit)); + dealloc_obj(treefruit); } exercise(A_DEX, TRUE); exercise(A_WIS, TRUE); /* discovered a new food source! */ diff -Naurd ../nethack-3.4.1/src/dothrow.c ./src/dothrow.c --- ../nethack-3.4.1/src/dothrow.c Sun Feb 23 14:43:26 2003 +++ ./src/dothrow.c Mon Sep 1 14:33:32 2003 @@ -5,6 +5,7 @@ /* Contains code for 't' (throw) */ #include "hack.h" +#include "edog.h" STATIC_DCL int FDECL(throw_obj, (struct obj *,int)); STATIC_DCL void NDECL(autoquiver); @@ -339,6 +340,7 @@ if (hero_breaks(obj, u.ux, u.uy, TRUE)) return; if (ship_object(obj, u.ux, u.uy, FALSE)) return; dropy(obj); + if (!u.uswallow) container_impact_dmg(obj); } /* @@ -447,6 +449,8 @@ return FALSE; } else if (!in_out_region(x, y)) { return FALSE; + } else if (*range == 0) { + return FALSE; /* previous step wants to stop now */ } if (!Passes_walls || !(may_pass = may_passwall(x, y))) { @@ -532,7 +536,8 @@ In_sokoban(&u.uz)) { /* Air currents overcome the recoil */ dotrap(ttmp,0); - return FALSE; + *range = 0; + return TRUE; } else { if (ttmp->tseen) You("pass right over %s %s.", @@ -815,10 +820,11 @@ struct obj *obj; { return (is_missile(obj) || is_spear(obj) || - /* daggers and knife (excludes scalpel) */ - (is_blade(obj) && (objects[obj->otyp].oc_dir & PIERCE)) || - /* special cases [might want to add AXE] */ - obj->otyp == WAR_HAMMER || obj->otyp == AKLYS); + /* daggers and knife (excludes scalpel) */ + (is_blade(obj) && !is_sword(obj) && + (objects[obj->otyp].oc_dir & PIERCE)) || + /* special cases [might want to add AXE] */ + obj->otyp == WAR_HAMMER || obj->otyp == AKLYS); } /* the currently thrown object is returning to you (not for boomerangs) */ @@ -1083,6 +1089,8 @@ newsym(bhitpos.x,bhitpos.y); if (obj_sheds_light(obj)) vision_full_recalc = 1; + if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ)) + container_impact_dmg(obj); } } @@ -1300,11 +1308,26 @@ sometimes disappear when thrown */ if (objects[otyp].oc_skill < P_NONE && objects[otyp].oc_skill > -P_BOOMERANG && - !objects[otyp].oc_magic && rn2(3)) { - if (*u.ushops) - check_shop_obj(obj, bhitpos.x,bhitpos.y, TRUE); - obfree(obj, (struct obj *)0); - return 1; + !objects[otyp].oc_magic) { + /* we were breaking 2/3 of everything unconditionally. + * we still don't want anything to survive unconditionally, + * but we need ammo to stay around longer on average. + */ + int broken, chance; + chance = 3 + greatest_erosion(obj) - obj->spe; + if (chance > 1) + broken = rn2(chance); + else + broken = !rn2(4); + if (obj->blessed && !rnl(4)) + broken = 0; + + if (broken) { + if (*u.ushops) + check_shop_obj(obj, bhitpos.x,bhitpos.y, TRUE); + obfree(obj, (struct obj *)0); + return 1; + } } passive_obj(mon, obj, (struct attack *)0); } else { @@ -1345,7 +1368,8 @@ potionhit(mon, obj, TRUE); return 1; - } else if (befriend_with_obj(mon->data, obj)) { + } else if (befriend_with_obj(mon->data, obj) || + (mon->mtame && dogfood(mon, obj) <= ACCFOOD)) { if (tamedog(mon, obj)) return 1; /* obj is gone */ else { diff -Naurd ../nethack-3.4.1/src/dungeon.c ./src/dungeon.c --- ../nethack-3.4.1/src/dungeon.c Sun Feb 23 14:43:26 2003 +++ ./src/dungeon.c Mon Sep 1 14:33:32 2003 @@ -44,7 +44,7 @@ STATIC_DCL boolean FDECL(place_level, (int, struct proto_dungeon *)); #ifdef WIZARD STATIC_DCL const char *FDECL(br_string, (int)); -STATIC_DCL void FDECL(print_branch, (winid, int, int, int)); +STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P, char *)); #endif #ifdef DEBUG @@ -1519,7 +1519,6 @@ return lev; } - #ifdef WIZARD /* Convert a branch type to a string usable by print_dungeon(). */ @@ -1538,14 +1537,17 @@ /* Print all child branches between the lower and upper bounds. */ STATIC_OVL void -print_branch(win, dnum, lower_bound, upper_bound) +print_branch(win, dnum, lower_bound, upper_bound, bymenu, menuletter) winid win; int dnum; int lower_bound; int upper_bound; + boolean bymenu; + char *menuletter; { branch *br; char buf[BUFSZ]; + anything any; /* This assumes that end1 is the "parent". */ for (br = branches; br; br = br->next) { @@ -1555,14 +1557,25 @@ br_string(br->type), dungeons[br->end2.dnum].dname, depth(&br->end1)); - putstr(win, 0, buf); + if (bymenu) { + schar lev = depth(&br->end1); + any.a_void = 0; + if (lev >= 0) any.a_schar = lev + 1; + else any.a_schar = lev; + add_menu(win, NO_GLYPH, &any, *menuletter, + 0, ATR_NONE, buf, MENU_UNSELECTED); + if (*menuletter == 'z') *menuletter = 'A'; + else *menuletter += 1; + } else + putstr(win, 0, buf); } } } /* Print available dungeon information. */ -void -print_dungeon() +schar +print_dungeon(bymenu) +boolean bymenu; { int i, last_level, nlev; char buf[BUFSZ]; @@ -1570,7 +1583,14 @@ s_level *slev; dungeon *dptr; branch *br; + + anything any; + char mlet; winid win = create_nhwindow(NHW_MENU); + if (bymenu) { + start_menu(win); + mlet = 'a'; + } for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) { nlev = dptr->num_dunlevs; @@ -1588,7 +1608,11 @@ Sprintf(eos(buf), ", entrance on %d", dptr->depth_start + dptr->entry_lev - 1); } - putstr(win, 0, buf); + if (bymenu) { + any.a_void = 0; + add_menu(win, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED); + } else + putstr(win, 0, buf); /* * Circle through the special levels to find levels that are in @@ -1598,31 +1622,70 @@ if (slev->dlevel.dnum != i) continue; /* print any branches before this level */ - print_branch(win, i, last_level, slev->dlevel.dlevel); + print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu, &mlet); Sprintf(buf, " %s: %d", slev->proto, depth(&slev->dlevel)); if (Is_stronghold(&slev->dlevel)) Sprintf(eos(buf), " (tune %s)", tune); - putstr(win, 0, buf); + if (bymenu) { + schar lev = depth(&slev->dlevel); + any.a_void = 0; + if (lev >= 0) any.a_schar = lev + 1; + else any.a_schar = lev; + add_menu(win, NO_GLYPH, &any, mlet, 0, ATR_NONE, buf, MENU_UNSELECTED); + if (mlet == 'z') mlet = 'A'; + else mlet++; + } else + putstr(win, 0, buf); last_level = slev->dlevel.dlevel; } /* print branches after the last special level */ - print_branch(win, i, last_level, MAXLEVEL); + print_branch(win, i, last_level, MAXLEVEL, bymenu, &mlet); } /* Print out floating branches (if any). */ for (first = TRUE, br = branches; br; br = br->next) { if (br->end1.dnum == n_dgns) { if (first) { - putstr(win, 0, ""); - putstr(win, 0, "Floating branches"); + if (bymenu) { + any.a_void = 0; + add_menu(win, NO_GLYPH, &any, 0, 0, ATR_BOLD, + "Floating branches", MENU_UNSELECTED); + } else { + putstr(win, 0, ""); + putstr(win, 0, "Floating branches"); + } first = FALSE; } Sprintf(buf, " %s to %s", br_string(br->type), dungeons[br->end2.dnum].dname); - putstr(win, 0, buf); + if (bymenu) { + schar lev = lev_by_name(dungeons[br->end2.dnum].dname); + any.a_void = 0; + if (lev >= 0) any.a_schar = lev + 1; + else any.a_schar = lev; + add_menu(win, NO_GLYPH, &any, mlet, 0, ATR_NONE, buf, MENU_UNSELECTED); + if (mlet == 'z') mlet = 'A'; + else mlet++; + } else + putstr(win, 0, buf); + } + } + if (bymenu) { + int n; + menu_item *selected; + schar lev = 0; + + end_menu(win, "Level teleport to where:"); + n = select_menu(win, PICK_ONE, &selected); + destroy_nhwindow(win); + if (n > 0) { + lev = selected[0].item.a_schar; + if (lev > 0) lev--; + free((genericptr_t)selected); } + return lev; } /* I hate searching for the invocation pos while debugging. -dean */ @@ -1654,6 +1717,7 @@ display_nhwindow(win, TRUE); destroy_nhwindow(win); + return 0; } #endif /* WIZARD */ diff -Naurd ../nethack-3.4.1/src/eat.c ./src/eat.c --- ../nethack-3.4.1/src/eat.c Sun Feb 23 14:43:26 2003 +++ ./src/eat.c Mon Sep 1 14:33:32 2003 @@ -258,6 +258,11 @@ killer = "a very rich meal"; } else { killer = food_xname(food, FALSE); + if (food->otyp == CORPSE && + (mons[food->corpsenm].geno & G_UNIQ)) { + killer = the(killer); + killer_format = KILLED_BY; + } } } else { You("choke over it."); @@ -815,6 +820,7 @@ case PM_STALKER: if(!Invis) { set_itimeout(&HInvis, (long)rn1(100, 50)); + if (!Blind && !BInvis) self_invis_message(); } else { if (!(HInvis & INTRINSIC)) You_feel("hidden!"); HInvis |= FROMOUTSIDE; @@ -848,7 +854,7 @@ #endif nomul(-tmp); Sprintf(buf, Hallucination ? - "You suddenly dread being peeled and mimick %s again!" : + "You suddenly dread being peeled and mimic %s again!" : "You now prefer mimicking %s again.", an(Upolyd ? youmonst.data->mname : urace.noun)); eatmbuf = strcpy((char *) alloc(strlen(buf) + 1), buf); @@ -1051,6 +1057,8 @@ !tin.tin->no_charge) || tin.tin->unpaid)) { verbalize("You open it, you bought it!"); + /* charge for one at pre-eating cost */ + if(tin.tin->quan > 1L) tin.tin = splitobj(tin.tin, 1L); bill_dummy_object(tin.tin); } @@ -1084,6 +1092,8 @@ !tin.tin->no_charge) || tin.tin->unpaid)) { verbalize("You open it, you bought it!"); + /* charge for one at pre-eating cost */ + if(tin.tin->quan > 1L) tin.tin = splitobj(tin.tin, 1L); bill_dummy_object(tin.tin); } @@ -1563,16 +1573,22 @@ { register struct obj *otmp = victual.piece; + /* lesshungry wants an occupation to handle choke messages correctly */ + set_occupation(eatfood, "eating non-food", 0); lesshungry(victual.nmod); + occupation = 0; victual.piece = (struct obj *)0; victual.eating = 0; if (otmp->oclass == COIN_CLASS) { #ifdef GOLDOBJ if (carried(otmp)) useupall(otmp); - else +#else + if (otmp->where == OBJ_FREE) + dealloc_obj(otmp); #endif - dealloc_obj(otmp); + else + useupf(otmp, otmp->quan); return; } if (otmp->oclass == POTION_CLASS) { @@ -1887,9 +1903,9 @@ stackobj(otmp); return 1; } - /* KMH -- Slow digestion is... undigestable */ + /* KMH -- Slow digestion is... indigestible */ if (otmp->otyp == RIN_SLOW_DIGESTION) { - pline("This ring is undigestable!"); + pline("This ring is indigestible!"); (void) rottenfood(otmp); if (otmp->dknown && !objects[otmp->otyp].oc_name_known && !objects[otmp->otyp].oc_uname) @@ -2405,7 +2421,6 @@ Sprintf(qbuf, "There are %ld gold pieces here; eat them?", gold->quan); if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { - obj_extract_self(gold); return gold; } else if (c == 'q') { return (struct obj *)0; diff -Naurd ../nethack-3.4.1/src/end.c ./src/end.c --- ../nethack-3.4.1/src/end.c Sun Feb 23 14:43:26 2003 +++ ./src/end.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)end.c 3.4 2003/01/08 */ +/* SCCS Id: @(#)end.c 3.4 2003/03/10 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -264,7 +264,9 @@ iflags.window_inited = 0; /* they're gone; force raw_print()ing */ } - raw_print(!program_state.something_worth_saving ? + raw_print(program_state.gameover ? + "Postgame wrapup disrupted." : + !program_state.something_worth_saving ? "Program initialization has failed." : "Suddenly, the dungeon collapses."); #if defined(WIZARD) && !defined(MICRO) @@ -919,8 +921,10 @@ char buf[BUFSZ]; for (box = list; box; box = box->nobj) { - if (Is_container(box) && box->otyp != BAG_OF_TRICKS) { - if (box->cobj) { + if (Is_container(box) || box->otyp == STATUE) { + if (box->otyp == BAG_OF_TRICKS) { + continue; /* wrong type of container */ + } else if (box->cobj) { winid tmpwin = create_nhwindow(NHW_MENU); Sprintf(buf, "Contents of %s:", the(xname(box))); putstr(tmpwin, 0, buf); diff -Naurd ../nethack-3.4.1/src/files.c ./src/files.c --- ../nethack-3.4.1/src/files.c Sun Feb 23 14:43:26 2003 +++ ./src/files.c Mon Sep 1 14:33:32 2003 @@ -91,6 +91,7 @@ #ifdef HOLD_LOCKFILE_OPEN struct level_ftrack { +int init; int fd; /* file descriptor for level file */ int oflag; /* open flags */ boolean nethack_thinks_it_is_open; /* Does NetHack think it's open? */ @@ -129,6 +130,10 @@ #endif #endif +#ifdef MAC +# define unlink macunlink +#endif + #ifdef USER_SOUNDS extern char *sounddir; #endif @@ -535,7 +540,11 @@ int lev, oflag; { int reslt, fd; - if (lftrack.fd) { + if (!lftrack.init) { + lftrack.init = 1; + lftrack.fd = -1; + } + if (lftrack.fd >= 0) { /* check for compatible access */ if (lftrack.oflag == oflag) { fd = lftrack.fd; @@ -554,7 +563,7 @@ fd = sopen(name, oflag,SH_DENYRW, FCMASK); lftrack.fd = fd; lftrack.oflag = oflag; - if (fd) + if (fd >= 0) lftrack.nethack_thinks_it_is_open = TRUE; } return fd; @@ -565,12 +574,13 @@ { int fd = lftrack.fd; lftrack.nethack_thinks_it_is_open = FALSE; - lftrack.fd = 0; + lftrack.fd = -1; lftrack.oflag = 0; (void)_close(fd); return; } +int close(fd) int fd; { @@ -924,6 +934,7 @@ return fd; } +#if defined(UNIX) && defined(QT_GRAPHICS) /*ARGSUSED*/ static char* plname_from_file(filename) @@ -956,13 +967,13 @@ (eg. "/", "_", and "." characters are lost. */ int k; int uid; - char name[NAME_MAX]; + char name[64]; /* more than PL_NSIZ */ #ifdef COMPRESS_EXTENSION #define EXTSTR COMPRESS_EXTENSION #else #define EXTSTR "" #endif - if ( sscanf( filename, "%*[^/]/%d%[^.]" EXTSTR, &uid, name ) == 2 ) { + if ( sscanf( filename, "%*[^/]/%d%63[^.]" EXTSTR, &uid, name ) == 2 ) { #undef EXTSTR /* "_" most likely means " ", which certainly looks nicer */ for (k=0; name[k]; k++) @@ -976,6 +987,7 @@ } #endif } +#endif /* defined(UNIX) && defined(QT_GRAPHICS) */ char** get_saved_games() @@ -989,8 +1001,8 @@ char** result = (char**)alloc((n+1)*sizeof(char*)); /* at most */ for (i=0; id_name, "%d%s", &uid, name ) == 2 ) { + char name[64]; /* more than PL_NSIZ */ + if ( sscanf( namelist[i]->d_name, "%d%63s", &uid, name ) == 2 ) { if ( uid == myuid ) { char filename[BUFSZ]; char* r; @@ -1349,15 +1361,21 @@ #endif /* UNIX || VMS */ #if defined(AMIGA) || defined(WIN32) || defined(MSDOS) +# ifdef AMIGA +#define OPENFAILURE(fd) (!fd) lockptr = 0; - while (retryct-- && !lockptr) { +# else +#define OPENFAILURE(fd) (fd < 0) + lockptr = -1; +# endif + while (retryct-- && OPENFAILURE(lockptr)) { # ifdef AMIGA (void)DeleteFile(lockname); /* in case dead process was here first */ lockptr = Open(lockname,MODE_NEWFILE); # else lockptr = open(lockname, O_RDWR|O_CREAT|O_EXCL, S_IWRITE); # endif - if (!lockptr) { + if (OPENFAILURE(lockptr)) { raw_printf("Waiting for access to %s. (%d retries left).", filename, retryct); Delay(50); @@ -1525,17 +1543,32 @@ # else /* should be only UNIX left */ envp = nh_getenv("HOME"); if (!envp) - Strcpy(tmp_config, ".nethackrc"); + Strcpy(tmp_config, configfile); else - Sprintf(tmp_config, "%s/%s", envp, ".nethackrc"); + Sprintf(tmp_config, "%s/%s", envp, configfile); if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) return(fp); - else if (errno != ENOENT) { - /* e.g., problems when setuid NetHack can't search home - * directory restricted to user */ - raw_printf("Couldn't open default config file %s (%d).", - tmp_config, errno); - wait_synch(); +# if defined(__APPLE__) + /* try an alternative */ + if (envp) { + Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults"); + if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) + return(fp); + } +# endif + if (errno != ENOENT) { + char *details; + + /* e.g., problems when setuid NetHack can't search home + * directory restricted to user */ + +#if defined (NHSTDC) && !defined(NOTSTDC) + if ((details = strerror(errno)) == 0) +#endif + details = ""; + raw_printf("Couldn't open default config file %s %s(%d).", + tmp_config, details, errno); + wait_synch(); } # endif #endif diff -Naurd ../nethack-3.4.1/src/fountain.c ./src/fountain.c --- ../nethack-3.4.1/src/fountain.c Sun Feb 23 14:43:26 2003 +++ ./src/fountain.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)fountain.c 3.4 2002/09/08 */ +/* SCCS Id: @(#)fountain.c 3.4 2003/03/23 */ /* Copyright Scott R. Turner, srt@ucla, 10/27/86 */ /* NetHack may be freely redistributed. See license for details. */ @@ -386,7 +386,7 @@ update_inventory(); levl[u.ux][u.uy].typ = ROOM; levl[u.ux][u.uy].looted = 0; - if(Invisible) newsym(u.ux, u.uy); + newsym(u.ux, u.uy); level.flags.nfountains--; if(in_town(u.ux, u.uy)) (void) angry_guards(FALSE); @@ -530,8 +530,9 @@ else { mtmp = makemon(&mons[PM_SEWER_RAT], u.ux, u.uy, NO_MM_FLAGS); - pline("Eek! There's %s in the sink!", - Blind ? "something squirmy" : + if (mtmp) pline("Eek! There's %s in the sink!", + (Blind || !canspotmon(mtmp)) ? + "something squirmy" : a_monnam(mtmp)); } break; diff -Naurd ../nethack-3.4.1/src/hack.c ./src/hack.c --- ../nethack-3.4.1/src/hack.c Sun Feb 23 14:43:27 2003 +++ ./src/hack.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)hack.c 3.4 2003/01/08 */ +/* SCCS Id: @(#)hack.c 3.4 2003/04/30 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -134,11 +134,13 @@ switch(ttmp->ttyp) { case LANDMINE: if (rn2(10)) { - pline("KAABLAMM!!! %s %s land mine.", - Tobjnam(otmp, "trigger"), - ttmp->madeby_u ? "your" : "a"); obj_extract_self(otmp); place_object(otmp, rx, ry); + unblock_point(sx, sy); + newsym(sx, sy); + pline("KAABLAMM!!! %s %s land mine.", + Tobjnam(otmp, "trigger"), + ttmp->madeby_u ? "your" : "a"); blow_up_landmine(ttmp); /* if the boulder remains, it should fill the pit */ fill_pit(u.ux, u.uy); @@ -738,8 +740,10 @@ int x = travelstepx[set][i]; int y = travelstepy[set][i]; static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 }; + /* no diagonal movement for grid bugs */ + int dirmax = u.umonnum == PM_GRID_BUG ? 4 : 8; - for (dir = 0; dir < 8; dir++) { + for (dir = 0; dir < dirmax; ++dir) { int nx = x+xdir[ordered[dir]]; int ny = y+ydir[ordered[dir]]; @@ -766,6 +770,7 @@ nomul(0); /* reset run so domove run checks work */ flags.run = 8; + iflags.travelcc.x = iflags.travelcc.y = -1; } return TRUE; } @@ -1897,7 +1902,10 @@ if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM) || IS_AIR(levl[x][y].typ)) continue; - else if (closed_door(x,y)) { + else if (closed_door(x,y) || + (mtmp && mtmp->m_ap_type == M_AP_FURNITURE && + (mtmp->mappearance == S_hcdoor || + mtmp->mappearance == S_vcdoor))) { if(x != u.ux && y != u.uy) continue; if(flags.run != 1) goto stop; goto bcorr; @@ -2102,7 +2110,7 @@ { register long carrcap; - carrcap = (((ACURRSTR + ACURR(A_CON))/2)+1)*50; + carrcap = 25*(ACURRSTR + ACURR(A_CON)) + 50; if (Upolyd) { /* consistent with can_carry() in mon.c */ if (youmonst.data->mlet == S_NYMPH) diff -Naurd ../nethack-3.4.1/src/hacklib.c ./src/hacklib.c --- ../nethack-3.4.1/src/hacklib.c Sun Feb 23 14:43:27 2003 +++ ./src/hacklib.c Mon Sep 1 14:33:32 2003 @@ -466,8 +466,8 @@ #ifdef RANDOM /* srandom() from sys/share/random.c */ srandom((unsigned int) time((time_t *)0)); #else -# if defined(__APPLE__) || defined(BSD) || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */ -# ifdef BSD +# if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */ +# if defined(BSD) && !defined(POSIX_TYPES) # if defined(SUNOS4) (void) # endif @@ -490,12 +490,12 @@ { time_t date; -#ifdef BSD +#if defined(BSD) && !defined(POSIX_TYPES) (void) time((long *)(&date)); #else (void) time(&date); #endif -#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD) +#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES)) return(localtime((long *)(&date))); #else return(localtime(&date)); @@ -542,7 +542,7 @@ if (date == 0) lt = getlt(); else -#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD) +#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES)) lt = localtime((long *)(&date)); #else lt = localtime(&date); diff -Naurd ../nethack-3.4.1/src/invent.c ./src/invent.c --- ../nethack-3.4.1/src/invent.c Sun Feb 23 14:43:27 2003 +++ ./src/invent.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)invent.c 3.4 2003/01/24 */ +/* SCCS Id: @(#)invent.c 3.4 2003/05/25 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -464,6 +464,17 @@ } } +/* use one charge from an item and possibly incur shop debt for it */ +void +consume_obj_charge(obj, maybe_unpaid) +struct obj *obj; +boolean maybe_unpaid; /* false if caller handles shop billing */ +{ + if (maybe_unpaid) check_unpaid(obj); + obj->spe -= 1; + if (obj->known) update_inventory(); +} + #endif /* OVLB */ #ifdef OVL3 @@ -968,7 +979,12 @@ } if(ilet == def_oc_syms[COIN_CLASS]) { if (!usegold) { - You("cannot %s gold.", word); + if (!strncmp(word, "rub on ", 7)) { + /* the dangers of building sentences... */ + You("cannot rub gold%s.", word + 3); + } else { + You("cannot %s gold.", word); + } return(struct obj *)0; #ifndef GOLDOBJ } else if (!allowgold) { @@ -1082,32 +1098,35 @@ 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; - } + const char *s1, *s2, *s3, *what; + int ocls = otmp->oclass, otyp = otmp->otyp; + + s1 = s2 = s3 = 0; + /* check for attempted use of accessory commands ('P','R') on armor + and for corresponding armor commands ('W','T') on accessories */ + if (ocls == ARMOR_CLASS) { + if (!strcmp(word, "put on")) + s1 = "W", s2 = "wear", s3 = ""; + else if (!strcmp(word, "remove")) + s1 = "T", s2 = "take", s3 = " off"; + } else if ((ocls == RING_CLASS || otyp == MEAT_RING) || + ocls == AMULET_CLASS || + (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) { + if (!strcmp(word, "wear")) + s1 = "P", s2 = "put", s3 = " on"; + else if (!strcmp(word, "take off")) + s1 = "R", s2 = "remove", s3 = ""; + } + if (s1) { + what = "that"; + /* quantity for armor and accessory objects is always 1, + but some things should be referred to as plural */ + if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp)) + what = "those"; + pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3); + } else { + pline(silly_thing_to, word); } - if (domsg) - pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3); - else - pline(silly_thing_to, word); } #endif /* OVL1 */ @@ -2143,7 +2162,7 @@ const char *dfeature = (char *)0; char fbuf[BUFSZ], fbuf2[BUFSZ]; winid tmpwin; - boolean skip_objects = (obj_cnt >= 5); + boolean skip_objects = (obj_cnt >= 5), felt_cockatrice = FALSE; if (u.uswallow && u.ustuck) { struct monst *mtmp = u.ustuck; @@ -2227,13 +2246,22 @@ putstr(tmpwin, 0, fbuf); putstr(tmpwin, 0, ""); } - putstr(tmpwin, 0, "Things that are here:"); + putstr(tmpwin, 0, Blind ? "Things that you feel here:" : + "Things that are here:"); for ( ; otmp; otmp = otmp->nexthere) { + if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) { + char buf[BUFSZ]; + felt_cockatrice = TRUE; + Strcpy(buf, doname(otmp)); + Strcat(buf, "..."); + putstr(tmpwin, 0, buf); + break; + } putstr(tmpwin, 0, doname(otmp)); - if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE); } display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); + if (felt_cockatrice) feel_cockatrice(otmp, FALSE); read_engr_at(u.ux, u.uy); /* Eric Backus */ } return(!!Blind); @@ -2246,6 +2274,17 @@ return look_here(0, FALSE); } +boolean +will_feel_cockatrice(otmp, force_touch) +struct obj *otmp; +boolean force_touch; +{ + if ((Blind || force_touch) && !uarmg && !Stone_resistance && + (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]))) + return TRUE; + return FALSE; +} + void feel_cockatrice(otmp, force_touch) struct obj *otmp; @@ -2253,8 +2292,7 @@ { char kbuf[BUFSZ]; - if ((Blind || force_touch) && !uarmg && !Stone_resistance && - (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]))) { + if (will_feel_cockatrice(otmp, force_touch)) { if(poly_when_stoned(youmonst.data)) You("touched the %s corpse with your bare %s.", mons[otmp->corpsenm].mname, makeplural(body_part(HAND))); @@ -2506,6 +2544,7 @@ long numused; { register struct obj *otmp; + boolean at_u = (obj->ox == u.ux && obj->oy == u.uy); /* burn_floor_paper() keeps an object pointer that it tries to * useupf() multiple times, so obj must survive if plural */ @@ -2519,6 +2558,8 @@ else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE); } delobj(otmp); + if (at_u && u.uundetected && hides_under(youmonst.data)) + u.uundetected = OBJ_AT(u.ux, u.uy); } #endif /* OVLB */ diff -Naurd ../nethack-3.4.1/src/light.c ./src/light.c --- ../nethack-3.4.1/src/light.c Sun Feb 23 14:43:27 2003 +++ ./src/light.c Mon Sep 1 14:33:32 2003 @@ -485,14 +485,7 @@ struct obj *obj; { return (obj->lamplit && - ( obj->otyp == MAGIC_LAMP - || obj->otyp == BRASS_LANTERN - || obj->otyp == OIL_LAMP - || obj->otyp == CANDELABRUM_OF_INVOCATION - || obj->otyp == TALLOW_CANDLE - || obj->otyp == WAX_CANDLE - || obj->otyp == POT_OIL - || artifact_light(obj))); + (obj->otyp == MAGIC_LAMP || ignitable(obj) || artifact_light(obj))); } /* copy the light source(s) attachted to src, and attach it/them to dest */ diff -Naurd ../nethack-3.4.1/src/lock.c ./src/lock.c --- ../nethack-3.4.1/src/lock.c Sun Feb 23 14:43:27 2003 +++ ./src/lock.c Mon Sep 1 14:33:32 2003 @@ -307,7 +307,9 @@ else if (picktyp != LOCK_PICK) verb = "unlock", it = 1; else verb = "pick"; Sprintf(qbuf, "There is %s here, %s %s?", - doname(otmp), verb, it ? "it" : "its lock"); + safe_qbuf("", sizeof("There is here, unlock its lock?"), + doname(otmp), an(simple_typename(otmp->otyp)), "a box"), + verb, it ? "it" : "its lock"); c = ynq(qbuf); if(c == 'q') return(0); @@ -353,6 +355,11 @@ } else { /* pick the lock in a door */ struct monst *mtmp; + if (u.utrap && u.utraptype == TT_PIT) { + You_cant("reach over the edge of the pit."); + return(0); + } + door = &levl[cc.x][cc.y]; if ((mtmp = m_at(cc.x, cc.y)) && canseemon(mtmp) && mtmp->m_ap_type != M_AP_FURNITURE @@ -464,7 +471,10 @@ doname(otmp), otmp->obroken ? "broken" : "unlocked"); continue; } - Sprintf(qbuf,"There is %s here, force its lock?", doname(otmp)); + Sprintf(qbuf,"There is %s here, force its lock?", + safe_qbuf("", sizeof("There is here, force its lock?"), + doname(otmp), an(simple_typename(otmp->otyp)), + "a box")); c = ynq(qbuf); if(c == 'q') return(0); diff -Naurd ../nethack-3.4.1/src/makemon.c ./src/makemon.c --- ../nethack-3.4.1/src/makemon.c Sun Feb 23 14:43:27 2003 +++ ./src/makemon.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)makemon.c 3.4 2002/02/07 */ +/* SCCS Id: @(#)makemon.c 3.4 2003/05/25 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -790,9 +790,18 @@ return((struct monst *)0); } - /* if a monster already exists at the position, return */ - if(MON_AT(x, y)) - return((struct monst *) 0); + /* Does monster already exist at the position? */ + if(MON_AT(x, y)) { + if ((mmflags & MM_ADJACENTOK) != 0) { + coord bypos; + if(enexto_core(&bypos, x, y, ptr, gpflags)) { + x = bypos.x; + y = bypos.y; + } else + return((struct monst *) 0); + } else + return((struct monst *) 0); + } if(ptr){ mndx = monsndx(ptr); @@ -1719,6 +1728,30 @@ mtmp->mappearance = appear; } +/* release a monster from a bag of tricks */ +void +bagotricks(bag) +struct obj *bag; +{ + if (!bag || bag->otyp != BAG_OF_TRICKS) { + impossible("bad bag o' tricks"); + } else if (bag->spe < 1) { + pline(nothing_happens); + } else { + boolean gotone = FALSE; + int cnt = 1; + + consume_obj_charge(bag, TRUE); + + if (!rn2(23)) cnt += rn1(7, 1); + while (cnt-- > 0) { + if (makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS)) + gotone = TRUE; + } + if (gotone) makeknown(BAG_OF_TRICKS); + } +} + #endif /* OVLB */ /*makemon.c*/ diff -Naurd ../nethack-3.4.1/src/mhitm.c ./src/mhitm.c --- ../nethack-3.4.1/src/mhitm.c Sun Feb 23 14:43:27 2003 +++ ./src/mhitm.c Mon Sep 1 14:33:32 2003 @@ -78,6 +78,8 @@ char buf[BUFSZ], mdef_name[BUFSZ]; if (vis) { + if (!canspotmon(magr)) + map_invisible(magr->mx, magr->my); if (!canspotmon(mdef)) map_invisible(mdef->mx, mdef->my); if (mdef->m_ap_type) seemimic(mdef); @@ -221,7 +223,7 @@ /* Set up the visibility of action */ - vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my)); + vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my) && (canspotmon(magr) || canspotmon(mdef))); /* Set flag indicating monster has moved this turn. Necessary since a * monster might get an attack out of sequence (i.e. before its move) in @@ -371,6 +373,8 @@ int compat; char buf[BUFSZ], mdef_name[BUFSZ]; + if (!canspotmon(magr)) + map_invisible(magr->mx, magr->my); if (!canspotmon(mdef)) map_invisible(mdef->mx, mdef->my); if(mdef->m_ap_type) seemimic(mdef); diff -Naurd ../nethack-3.4.1/src/mhitu.c ./src/mhitu.c --- ../nethack-3.4.1/src/mhitu.c Sun Feb 23 14:43:27 2003 +++ ./src/mhitu.c Mon Sep 1 14:33:32 2003 @@ -783,6 +783,7 @@ if (obj->greased && !rn2(2)) { pline_The("grease wears off."); obj->greased = 0; + update_inventory(); } return TRUE; } @@ -1207,7 +1208,7 @@ killer_format = KILLED_BY_AN; Sprintf(buf, "%s by %s", moat ? "moat" : "pool of water", - a_monnam(mtmp)); + an(mtmp->data->mname)); killer = buf; done(DROWNING); } else if(mattk->aatyp == AT_HUGS) @@ -1683,8 +1684,14 @@ } break; case AD_PHYS: - You("are pummeled with debris!"); - exercise(A_STR, FALSE); + if (mtmp->data == &mons[PM_FOG_CLOUD]) + You("are laden with moisture and can barely %s!", + !breathless(youmonst.data) ? "breathe" : + "stay conscious"); + else { + You("are pummeled with debris!"); + exercise(A_STR, FALSE); + } break; case AD_ACID: if (Acid_resistance) { @@ -2142,7 +2149,8 @@ if (fem) { if (rn2(20) < ACURR(A_CHA)) { Sprintf(qbuf, "\"That %s looks pretty. May I have it?\"", - xname(ring)); + safe_qbuf("",sizeof("\"That looks pretty. May I have it?\""), + xname(ring), simple_typename(ring->otyp), "ring")); makeknown(RIN_ADORNMENT); if (yn(qbuf) == 'n') continue; } else pline("%s decides she'd like your %s, and takes it.", @@ -2163,7 +2171,9 @@ if (ring==uleft || ring==uright) continue; if (rn2(20) < ACURR(A_CHA)) { Sprintf(qbuf,"\"That %s looks pretty. Would you wear it for me?\"", - xname(ring)); + safe_qbuf("", + sizeof("\"That looks pretty. Would you wear it for me?\""), + xname(ring), simple_typename(ring->otyp), "ring")); makeknown(RIN_ADORNMENT); if (yn(qbuf) == 'n') continue; } else { diff -Naurd ../nethack-3.4.1/src/mklev.c ./src/mklev.c --- ../nethack-3.4.1/src/mklev.c Sun Feb 23 14:43:27 2003 +++ ./src/mklev.c Mon Sep 1 14:33:32 2003 @@ -485,7 +485,7 @@ trap_type = ROCKTRAP; ttmp = maketrap(xx, yy+dy, trap_type); if (ttmp) { - ttmp->once = 1; + if (trap_type != ROCKTRAP) ttmp->once = 1; if (trap_engravings[trap_type]) { make_engr_at(xx, yy-dy, trap_engravings[trap_type], 0L, DUST); diff -Naurd ../nethack-3.4.1/src/mkmap.c ./src/mkmap.c --- ../nethack-3.4.1/src/mkmap.c Sun Feb 23 14:43:27 2003 +++ ./src/mkmap.c Mon Sep 1 14:33:32 2003 @@ -17,6 +17,7 @@ STATIC_DCL void NDECL(wallify_map); STATIC_DCL void FDECL(join_map,(SCHAR_P,SCHAR_P)); STATIC_DCL void FDECL(finish_map,(SCHAR_P,SCHAR_P,XCHAR_P,XCHAR_P)); +STATIC_DCL void FDECL(remove_room,(unsigned)); void FDECL(mkmap, (lev_init *)); char *new_locations; @@ -361,13 +362,92 @@ levl[i][j].lit = TRUE; } +/* + * When level processed by join_map is overlaid by a MAP, some rooms may no + * longer be valid. All rooms in the region lx <= x < hx, ly <= y < hy are + * removed. Rooms partially in the region are truncated. This function + * must be called before the REGIONs or ROOMs of the map are processed, or + * those rooms will be removed as well. Assumes roomno fields in the + * region are already cleared, and roomno and irregular fields outside the + * region are all set. + */ +void +remove_rooms(lx, ly, hx, hy) + int lx, ly, hx, hy; +{ + int i; + struct mkroom *croom; + + for (i = nroom - 1; i >= 0; --i) { + croom = &rooms[i]; + if (croom->hx < lx || croom->lx >= hx || + croom->hy < ly || croom->ly >= hy) continue; /* no overlap */ + + if (croom->lx < lx || croom->hx >= hx || + croom->ly < ly || croom->hy >= hy) { /* partial overlap */ + /* TODO: ensure remaining parts of room are still joined */ + + if (!croom->irregular) impossible("regular room in joined map"); + + /* if a "donut" or even disconnected room, leave bounds alone */ + if ((croom->lx < lx && croom->hx >= hx) || + (croom->ly < ly && croom->hy >= hy)) { + continue; + } + + /* truncate the side(s) that are covered by the region */ + if (croom->lx < lx && croom->hx < hx) croom->hx = lx - 1; + if (croom->lx >= lx && croom->hx >= hx) croom->lx = hx; + if (croom->ly < ly && croom->hy < hy) croom->hy = ly - 1; + if (croom->ly >= ly && croom->hy >= hy) croom->ly = hy; + } else { + /* total overlap, remove the room */ + remove_room((unsigned)i); + } + } +} + +/* + * Remove roomno from the rooms array, decrementing nroom. Also updates + * all level roomno values of affected higher numbered rooms. Assumes + * level structure contents corresponding to roomno have already been reset. + * Currently handles only the removal of rooms that have no subrooms. + */ +STATIC_OVL void +remove_room(roomno) + unsigned roomno; +{ + struct mkroom *croom = &rooms[roomno]; + struct mkroom *maxroom = &rooms[--nroom]; + int i, j; + unsigned oroomno; + + if (croom != maxroom) { + /* since the order in the array only matters for making corridors, + * copy the last room over the one being removed on the assumption + * that corridors have already been dug. */ + (void) memcpy((genericptr_t)croom, (genericptr_t)maxroom, + sizeof(struct mkroom)); + + /* since maxroom moved, update affected level roomno values */ + oroomno = nroom + ROOMOFFSET; + roomno += ROOMOFFSET; + for (i = croom->lx; i <= croom->hx; ++i) + for (j = croom->ly; j <= croom->hy; ++j) { + if (levl[i][j].roomno == oroomno) + levl[i][j].roomno = roomno; + } + } + + maxroom->hx = -1; /* just like add_room */ +} + #define N_P1_ITER 1 /* tune map generation via this value */ #define N_P2_ITER 1 /* tune map generation via this value */ #define N_P3_ITER 2 /* tune map smoothing via this value */ void mkmap(init_lev) - lev_init *init_lev; { schar bg_typ = init_lev->bg, diff -Naurd ../nethack-3.4.1/src/mkobj.c ./src/mkobj.c --- ../nethack-3.4.1/src/mkobj.c Sun Feb 23 14:43:28 2003 +++ ./src/mkobj.c Mon Sep 1 14:33:32 2003 @@ -416,7 +416,7 @@ this level; let's create an adventurer's corpse instead, then */ otmp->corpsenm = PM_HUMAN; } - start_corpse_timeout(otmp); + /* timer set below */ break; case EGG: otmp->corpsenm = NON_PM; /* generic egg */ @@ -617,6 +617,14 @@ objects[otmp->otyp].oc_class); return (struct obj *)0; } + + /* Some things must get done (timers) even if init = 0 */ + switch (otmp->otyp) { + case CORPSE: + start_corpse_timeout(otmp); + break; + } + /* unique objects may have an associated artifact entry */ if (objects[otyp].oc_unique && !otmp->oartifact) otmp = mk_artifact(otmp, (aligntyp)A_NONE); diff -Naurd ../nethack-3.4.1/src/mkroom.c ./src/mkroom.c --- ../nethack-3.4.1/src/mkroom.c Sun Feb 23 14:43:28 2003 +++ ./src/mkroom.c Mon Sep 1 14:33:32 2003 @@ -128,8 +128,10 @@ } #endif } +#ifndef MAC gottype: #endif +#endif for(sroom = &rooms[0]; ; sroom++){ if(sroom->hx < 0) return; if(sroom - rooms >= nroom) { diff -Naurd ../nethack-3.4.1/src/mon.c ./src/mon.c --- ../nethack-3.4.1/src/mon.c Sun Feb 23 14:43:28 2003 +++ ./src/mon.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)mon.c 3.4 2003/01/29 */ +/* SCCS Id: @(#)mon.c 3.4 2003/08/24 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -84,6 +84,47 @@ return mndx; } +/* Convert the monster index of some monsters (such as quest guardians) + * to their generic species type. + * + * Return associated character class monster, rather than species + * if mode is 1. + */ +int +genus(mndx, mode) +int mndx, mode; +{ + switch (mndx) { +/* Quest guardians */ + case PM_STUDENT: mndx = mode ? PM_VALKYRIE : PM_HUMAN; break; + case PM_CHIEFTAIN: mndx = mode ? PM_BARBARIAN : PM_HUMAN; break; + case PM_NEANDERTHAL: mndx = mode ? PM_CAVEMAN : PM_HUMAN; break; + case PM_ATTENDANT: mndx = mode ? PM_HEALER : PM_HUMAN; break; + case PM_PAGE: mndx = mode ? PM_KNIGHT : PM_HUMAN; break; + case PM_ABBOT: mndx = mode ? PM_MONK : PM_HUMAN; break; + case PM_ACOLYTE: mndx = mode ? PM_PRIEST : PM_HUMAN; break; + case PM_HUNTER: mndx = mode ? PM_RANGER : PM_HUMAN; break; + case PM_THUG: mndx = mode ? PM_ROGUE : PM_HUMAN; break; + case PM_ROSHI: mndx = mode ? PM_SAMURAI : PM_HUMAN; break; +#ifdef TOURIST + case PM_GUIDE: mndx = mode ? PM_TOURIST : PM_HUMAN; break; +#endif + case PM_APPRENTICE: mndx = mode ? PM_WIZARD : PM_HUMAN; break; + case PM_WARRIOR: mndx = mode ? PM_VALKYRIE : PM_HUMAN; break; + default: + if (mndx >= LOW_PM && mndx < NUMMONS) { + struct permonst *ptr = &mons[mndx]; + if (is_human(ptr)) mndx = PM_HUMAN; + else if (is_elf(ptr)) mndx = PM_ELF; + else if (is_dwarf(ptr)) mndx = PM_DWARF; + else if (is_gnome(ptr)) mndx = PM_GNOME; + else if (is_orc(ptr)) mndx = PM_ORC; + } + break; + } + return mndx; +} + /* convert monster index to chameleon index */ int pm_to_cham(mndx) @@ -640,7 +681,7 @@ pline("%s spits %s out in disgust!", Monnam(mtmp), distant_name(otmp,doname)); } - /* KMH -- Don't eat undigestable/choking objects */ + /* KMH -- Don't eat indigestible/choking objects */ } else if (otmp->otyp != AMULET_OF_STRANGULATION && otmp->otyp != RIN_SLOW_DIGESTION) { if (cansee(mtmp->mx,mtmp->my) && flags.verbose) @@ -1586,8 +1627,7 @@ /* 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); + otmp = mkcorpstat(STATUE, mdef, mdef->data, x, y, FALSE); if (mdef->mnamelth) otmp = oname(otmp, NAME(mdef)); while ((obj = oldminvent) != 0) { oldminvent = obj->nobj; @@ -1958,13 +1998,13 @@ void poisoned(string, typ, pname, fatal) -register const char *string, *pname; -register int typ, fatal; +const char *string, *pname; +int typ, fatal; { - register int i, plural; - boolean thrown_weapon = !strncmp(string, "poison", 6); - /* admittedly a kludge... */ + int i, plural, kprefix = KILLED_BY_AN; + boolean thrown_weapon = (fatal < 0); + if (thrown_weapon) fatal = -fatal; if(strcmp(string, "blast") && !thrown_weapon) { /* 'blast' has already given a 'poison gas' message */ /* so have "poison arrow", "poison dart", etc... */ @@ -1979,6 +2019,15 @@ pline_The("poison doesn't seem to affect you."); return; } + /* suppress killer prefix if it already has one */ + if (!strncmpi(pname, "the ", 4) || + !strncmpi(pname, "an ", 3) || + !strncmpi(pname, "a ", 2) || + /* ... or if it seems to be a proper name */ + isupper(*pname)) { + /*[ does this need a plural check too? ]*/ + kprefix = KILLED_BY; + } i = rn2(fatal + 20*thrown_weapon); if(i == 0 && typ != A_CHA) { u.uhp = -1; @@ -1986,17 +2035,17 @@ } else if(i <= 5) { /* Check that a stat change was made */ if (adjattrib(typ, thrown_weapon ? -1 : -rn1(3,3), 1)) - pline("You%s!", poiseff[typ]); + pline("You%s!", poiseff[typ]); } else { i = thrown_weapon ? rnd(6) : rn1(10,6); if(Half_physical_damage) i = (i+1) / 2; - losehp(i, pname, KILLED_BY_AN); + losehp(i, pname, kprefix); } if(u.uhp < 1) { - killer_format = KILLED_BY_AN; + killer_format = kprefix; killer = pname; /* "Poisoned by a poisoned ___" is redundant */ - done(thrown_weapon ? DIED : POISONING); + done(strstri(pname, "poison") ? DIED : POISONING); } (void) encumber_msg(); } diff -Naurd ../nethack-3.4.1/src/mondata.c ./src/mondata.c --- ../nethack-3.4.1/src/mondata.c Sun Feb 23 14:43:28 2003 +++ ./src/mondata.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)mondata.c 3.4 2003/01/08 */ +/* SCCS Id: @(#)mondata.c 3.4 2003/06/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -523,20 +523,29 @@ pronoun_gender(mtmp) register struct monst *mtmp; { - if (!canspotmon(mtmp) || !humanoid(mtmp->data)) - return 2; - return mtmp->female; + if (is_neuter(mtmp->data) || !canspotmon(mtmp)) return 2; + return (humanoid(mtmp->data) || (mtmp->data->geno & G_UNIQ) || + type_is_pname(mtmp->data)) ? (int)mtmp->female : 2; } #endif /* OVL2 */ #ifdef OVLB +/* used for nearby monsters when you go to another level */ boolean levl_follower(mtmp) -register struct monst *mtmp; +struct monst *mtmp; { - return((boolean)(mtmp->mtame || (mtmp->data->mflags2 & M2_STALK) || is_fshk(mtmp) - || (mtmp->iswiz && !mon_has_amulet(mtmp)))); + /* monsters with the Amulet--even pets--won't follow across levels */ + if (mon_has_amulet(mtmp)) return FALSE; + + /* some monsters will follow even while intending to flee from you */ + if (mtmp->mtame || mtmp->iswiz || is_fshk(mtmp)) return TRUE; + + /* stalking types follow, but won't when fleeing unless you hold + the Amulet */ + return (boolean)((mtmp->data->mflags2 & M2_STALK) && + (!mtmp->mflee || u.uhave.amulet)); } static const short grownups[][2] = { diff -Naurd ../nethack-3.4.1/src/monmove.c ./src/monmove.c --- ../nethack-3.4.1/src/monmove.c Sun Feb 23 14:43:28 2003 +++ ./src/monmove.c Mon Sep 1 14:33:32 2003 @@ -116,6 +116,7 @@ /* can see it now, or sense it and would normally see it */ (canseemon(mtmp) || (sensemon(mtmp) && couldsee(mtmp->mx,mtmp->my))) && + mtmp->mcanmove && !noattacks(mtmp->data) && !onscary(u.ux, u.uy, mtmp)) stop_occupation(); diff -Naurd ../nethack-3.4.1/src/mthrowu.c ./src/mthrowu.c --- ../nethack-3.4.1/src/mthrowu.c Sun Feb 23 14:43:28 2003 +++ ./src/mthrowu.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)mthrowu.c 3.4 2002/11/07 */ +/* SCCS Id: @(#)mthrowu.c 3.4 2003/05/09 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -41,30 +41,21 @@ { const char *onm, *knm; boolean is_acid; + int kprefix = KILLED_BY_AN; char onmbuf[BUFSZ], knmbuf[BUFSZ]; if (!name) { - struct obj otmp; - unsigned save_ocknown; - if (!obj) panic("thitu: name & obj both null?"); name = strcpy(onmbuf, (obj->quan > 1L) ? doname(obj) : mshot_xname(obj)); - /* killer name should be more specific; however, exact info - like blessed/cursed and rustproof make things too verbose */ - otmp = *obj; - save_ocknown = objects[otmp.otyp].oc_name_known; - otmp.known = otmp.dknown = 1; - otmp.bknown = otmp.rknown = otmp.greased = 0; - /* "killed by poisoned " would be misleading - since poison is not the cause of death */ - otmp.opoisoned = 0; - objects[otmp.otyp].oc_name_known = 1; - knm = strcpy(knmbuf, - (otmp.quan > 1L) ? doname(&otmp) : xname(&otmp)); - objects[otmp.otyp].oc_name_known = save_ocknown; + knm = strcpy(knmbuf, killer_xname(obj)); + kprefix = KILLED_BY; /* killer_name supplies "an" if warranted */ } else { knm = name; + /* [perhaps ought to check for plural here to] */ + if (!strncmpi(name, "the ", 4) || + !strncmpi(name, "an ", 3) || + !strncmpi(name, "a ", 2)) kprefix = KILLED_BY; } onm = (obj && obj_is_pname(obj)) ? the(name) : (obj && obj->quan > 1L) ? name : an(name); @@ -89,8 +80,7 @@ else { if (is_acid) pline("It burns!"); if (Half_physical_damage) dam = (dam+1) / 2; - losehp(dam, knm, (obj && obj_is_pname(obj)) ? - KILLED_BY : KILLED_BY_AN); + losehp(dam, knm, kprefix); exercise(A_STR, FALSE); } return(1); @@ -393,21 +383,10 @@ if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) { char onmbuf[BUFSZ], knmbuf[BUFSZ]; - struct obj otmp; - unsigned save_ocknown; - /* [see thitu()'s handling of `name'] */ Strcpy(onmbuf, xname(singleobj)); - otmp = *singleobj; - save_ocknown = objects[otmp.otyp].oc_name_known; - otmp.known = otmp.dknown = 1; - otmp.bknown = otmp.rknown = otmp.greased = 0; - /* "poisoned by poisoned " would be redundant */ - otmp.opoisoned = 0; - objects[otmp.otyp].oc_name_known = 1; - Strcpy(knmbuf, xname(&otmp)); - poisoned(onmbuf, A_STR, knmbuf, 10); - objects[otmp.otyp].oc_name_known = save_ocknown; + Strcpy(knmbuf, killer_xname(singleobj)); + poisoned(onmbuf, A_STR, knmbuf, -10); } if(hitu && can_blnd((struct monst*)0, &youmonst, diff -Naurd ../nethack-3.4.1/src/music.c ./src/music.c --- ../nethack-3.4.1/src/music.c Sun Feb 23 14:43:28 2003 +++ ./src/music.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)music.c 3.4 2001/12/03 */ +/* SCCS Id: @(#)music.c 3.4 2003/05/25 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -384,8 +384,8 @@ switch (instr->otyp) { case MAGIC_FLUTE: /* Make monster fall asleep */ if (do_spec && instr->spe > 0) { - check_unpaid(instr); - instr->spe--; + consume_obj_charge(instr, TRUE); + You("produce soft music."); put_monsters_to_sleep(u.ulevel * 5); exercise(A_DEX, TRUE); @@ -400,8 +400,8 @@ case FROST_HORN: /* Idem wand of cold */ case FIRE_HORN: /* Idem wand of fire */ if (do_spec && instr->spe > 0) { - check_unpaid(instr); - instr->spe--; + consume_obj_charge(instr, TRUE); + if (!getdir((char *)0)) { pline("%s.", Tobjnam(instr, "vibrate")); break; @@ -430,8 +430,8 @@ break; case MAGIC_HARP: /* Charm monsters */ if (do_spec && instr->spe > 0) { - check_unpaid(instr); - instr->spe--; + consume_obj_charge(instr, TRUE); + pline("%s very attractive music.", Tobjnam(instr, "produce")); charm_monsters((u.ulevel - 1) / 3 + 1); exercise(A_DEX, TRUE); @@ -446,8 +446,8 @@ break; case DRUM_OF_EARTHQUAKE: /* create several pits */ if (do_spec && instr->spe > 0) { - check_unpaid(instr); - instr->spe--; + consume_obj_charge(instr, TRUE); + You("produce a heavy, thunderous rolling!"); pline_The("entire dungeon is shaking around you!"); do_earthquake((u.ulevel - 1) / 3 + 1); @@ -477,9 +477,7 @@ struct obj *instr; { char buf[BUFSZ], c = 'y'; -#ifndef AMIGA - char *s; -#endif + char *s; int x,y; boolean ok; @@ -491,14 +489,22 @@ c = yn("Improvise?"); } if (c == 'n') { - if (u.uevent.uheard_tune == 2 && yn("Play the passtune?") == 'y') - Strcpy(buf, tune); - else - getlin("What tune are you playing? [what 5 notes]", buf); -#ifndef AMIGA - /* The AMIGA supports two octaves of notes */ - for (s=buf; *s; s++) *s = highc(*s); + if (u.uevent.uheard_tune == 2 && yn("Play the passtune?") == 'y') { + Strcpy(buf, tune); + } else { + getlin("What tune are you playing? [5 notes, A-G]", buf); + (void)mungspaces(buf); + /* convert to uppercase and change any "H" to the expected "B" */ + for (s = buf; *s; s++) { +#ifndef AMIGA + *s = highc(*s); +#else + /* The AMIGA supports two octaves of notes */ + if (*s == 'h') *s = 'b'; #endif + if (*s == 'H') *s = 'B'; + } + } You("extract a strange sound from %s!", the(xname(instr))); #ifdef UNIX386MUSIC /* if user is at the console, play through the console speaker */ diff -Naurd ../nethack-3.4.1/src/objnam.c ./src/objnam.c --- ../nethack-3.4.1/src/objnam.c Sun Feb 23 14:43:28 2003 +++ ./src/objnam.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)objnam.c 3.4 2003/02/08 */ +/* SCCS Id: @(#)objnam.c 3.4 2003/05/09 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -367,7 +367,7 @@ case ROCK_CLASS: if (typ == STATUE) Sprintf(buf, "%s%s of %s%s", - (Role_if(PM_ARCHEOLOGIST) && obj->spe) ? "historic " : "" , + (Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC)) ? "historic " : "" , actualn, type_is_pname(&mons[obj->corpsenm]) ? "" : (mons[obj->corpsenm].geno & G_UNIQ) ? "the " : @@ -854,6 +854,47 @@ return xname(obj); } +/* treat an object as fully ID'd when it might be used as reason for death */ +char * +killer_xname(obj) +struct obj *obj; +{ + struct obj save_obj; + unsigned save_ocknown; + char *buf, *save_ocuname; + + /* remember original settings for core of the object; + oname and oattached extensions don't matter here--since they + aren't modified they don't need to be saved and restored */ + save_obj = *obj; + /* killer name should be more specific than general xname; however, exact + info like blessed/cursed and rustproof makes things be too verbose */ + obj->known = obj->dknown = 1; + obj->bknown = obj->rknown = obj->greased = 0; + /* if character is a priest[ess], bknown will get toggled back on */ + obj->blessed = obj->cursed = 0; + /* "killed by poisoned " would be misleading when poison is + not the cause of death and "poisoned by poisoned " would + be redundant when it is, so suppress "poisoned" prefix */ + obj->opoisoned = 0; + /* strip user-supplied name; artifacts keep theirs */ + if (!obj->oartifact) obj->onamelth = 0; + /* temporarily identify the type of object */ + save_ocknown = objects[obj->otyp].oc_name_known; + objects[obj->otyp].oc_name_known = 1; + save_ocuname = objects[obj->otyp].oc_uname; + objects[obj->otyp].oc_uname = 0; /* avoid "foo called bar" */ + + buf = xname(obj); + if (obj->quan == 1L) buf = obj_is_pname(obj) ? the(buf) : an(buf); + + objects[obj->otyp].oc_name_known = save_ocknown; + objects[obj->otyp].oc_uname = save_ocuname; + *obj = save_obj; /* restore object's core settings */ + + return buf; +} + /* * Used if only one of a collection of objects is named (e.g. in eat.c). */ @@ -1049,7 +1090,7 @@ register const char *verb; { char *buf = nextobuf(); - int len; + int len, ltmp; const char *sp, *spot; const char * const *spec; @@ -1064,6 +1105,8 @@ * present tense form so we don't duplicate this code elsewhere. */ if (subj) { + if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3)) + goto sing; spot = (const char *)0; for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) { if (!strncmp(sp, " of ", 4) || @@ -1090,15 +1133,23 @@ ((spot - subj) >= 2 && !strncmp(spot-1, "ae", 2))) { /* 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; + for (spec = special_subjs; *spec; spec++) { + ltmp = strlen(*spec); + if (len == ltmp && !strncmpi(*spec, subj, len)) goto sing; + /* also check for + to catch things like "the invisible erinys" */ + if (len > ltmp && *(spot - ltmp) == ' ' && + strncmpi(*spec, spot - ltmp + 1, ltmp)) goto sing; + } return strcpy(buf, verb); } /* + * 3rd person plural doesn't end in telltale 's'; * 2nd person singular behaves as if plural. */ - if (!strcmpi(subj, "you")) return strcpy(buf, verb); + if (!strcmpi(subj, "they") || !strcmpi(subj, "you")) + return strcpy(buf, verb); } sing: @@ -1161,6 +1212,32 @@ return s; } +/* returns "your simple_typename(obj->otyp)" + * or "Foobar's simple_typename(obj->otyp)" + * or "the simple_typename(obj-otyp)" + */ +char * +ysimple_name(obj) +struct obj *obj; +{ + char *outbuf = nextobuf(); + char *s = shk_your(outbuf, obj); /* assert( s == outbuf ); */ + int space_left = BUFSZ - strlen(s) - sizeof " "; + + return strncat(strcat(s, " "), simple_typename(obj->otyp), space_left); +} + +/* capitalized variant of ysimple_name() */ +char * +Ysimple_name2(obj) +struct obj *obj; +{ + char *s = ysimple_name(obj); + + *s = highc(*s); + return s; +} + static const char *wrp[] = { "wand", "ring", "potion", "scroll", "gem", "amulet", "spellbook", "spell book", @@ -1936,6 +2013,7 @@ if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */ if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */ if (strncmpi(bp, "master key", 10)) /* not the "master" rank */ + if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */ if (mntmp < LOW_PM && strlen(bp) > 2 && (mntmp = name_to_mon(bp)) >= LOW_PM) { int mntmptoo, mntmplen; /* double check for rank title */ @@ -2479,7 +2557,10 @@ /* beware of random troll or lizard corpse, or of ordinary one being forced to such */ if (otmp->timed) obj_stop_timers(otmp); - otmp->corpsenm = mntmp; + if (mons[mntmp].msound == MS_GUARDIAN) + otmp->corpsenm = genus(mntmp,1); + else + otmp->corpsenm = mntmp; start_corpse_timeout(otmp); } break; @@ -2505,7 +2586,7 @@ case STATUE: otmp->corpsenm = mntmp; if (Has_contents(otmp) && verysmall(&mons[mntmp])) delete_contents(otmp); /* no spellbook */ - otmp->spe = ishistoric; + otmp->spe = ishistoric ? STATUE_HISTORIC : 0; break; case SCALE_MAIL: /* Dragon mail - depends on the order of objects */ diff -Naurd ../nethack-3.4.1/src/options.c ./src/options.c --- ../nethack-3.4.1/src/options.c Sun Feb 23 14:43:28 2003 +++ ./src/options.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)options.c 3.4 2003/01/08 */ +/* SCCS Id: @(#)options.c 3.4 2003/05/19 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -98,6 +98,7 @@ #else {"flush", (boolean *)0, FALSE, SET_IN_FILE}, #endif + {"fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE}, {"help", &flags.help, TRUE, SET_IN_GAME}, {"hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME}, /*WC*/ #ifdef ASCIIGRAPH @@ -137,7 +138,6 @@ {"news", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"null", &flags.null, TRUE, SET_IN_GAME}, - {"number_pad", &iflags.num_pad, FALSE, SET_IN_GAME}, #ifdef MAC {"page_wait", &flags.page_wait, TRUE, SET_IN_GAME}, #else @@ -172,6 +172,7 @@ {"showscore", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"silent", &flags.silent, TRUE, SET_IN_GAME}, + {"softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE}, {"sortpack", &flags.sortpack, TRUE, SET_IN_GAME}, {"sound", &flags.soundok, TRUE, SET_IN_GAME}, {"sparkle", &flags.sparkle, TRUE, SET_IN_GAME}, @@ -208,6 +214,7 @@ 8, DISP_IN_GAME }, { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/ { "align_status", "status window alignment", 20, DISP_IN_GAME }, /*WC*/ + { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME }, { "boulder", "the symbol to use for displaying boulders", 1, SET_IN_GAME }, { "catname", "the name of your (first) cat (e.g., catname:Tabby)", @@ -226,10 +233,10 @@ { "font_message", "the font to use in the message window", 40, DISP_IN_GAME }, /*WC*/ { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/ - { "font_size_menu", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/ - { "font_size_message", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/ - { "font_size_status", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/ - { "font_size_text", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/ + { "font_size_menu", "the size of the menu font", 20, DISP_IN_GAME }, /*WC*/ + { "font_size_message", "the size of the message font", 20, DISP_IN_GAME }, /*WC*/ + { "font_size_status", "the size of the status font", 20, DISP_IN_GAME }, /*WC*/ + { "font_size_text", "the size of the text font", 20, DISP_IN_GAME }, /*WC*/ { "font_status", "the font to use in status window", 40, DISP_IN_GAME }, /*WC*/ { "font_text", "the font to use in text windows", 40, DISP_IN_GAME }, /*WC*/ { "fruit", "the name of a fruit you enjoy eating", @@ -267,6 +274,7 @@ # endif { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ, DISP_IN_GAME }, + { "number_pad", "use the number pad", 1, SET_IN_GAME}, { "objects", "the symbols to use for objects", MAXOCLASSES, SET_IN_FILE }, { "packorder", "the inventory order of the items in your pack", @@ -290,11 +298,11 @@ 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'", + { "runmode", "display 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", + { "scroll_amount", "amount to scroll map 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 @@ -424,6 +435,8 @@ STATIC_OVL int FDECL(wc_set_window_colors, (char *)); STATIC_OVL boolean FDECL(is_wc_option, (const char *)); STATIC_OVL boolean FDECL(wc_supported, (const char *)); +STATIC_OVL boolean FDECL(is_wc2_option, (const char *)); +STATIC_OVL boolean FDECL(wc2_supported, (const char *)); /* check whether a user-supplied option string is a proper leading substring of a particular option name; option string might have @@ -470,7 +483,9 @@ void initoptions() { +#ifndef MAC char *opts; +#endif int i; /* initialize the random number generator */ @@ -507,6 +522,7 @@ for (i = 0; i < WARNCOUNT; i++) warnsyms[i] = def_warnsyms[i].sym; iflags.bouldersym = 0; + iflags.travelcc.x = iflags.travelcc.y = -1; flags.warnlevel = 1; flags.warntype = 0L; @@ -981,6 +997,7 @@ if (match_optname(opts, "colour", 5, FALSE)) Strcpy(opts, "color"); /* fortunately this isn't longer */ + if (!match_optname(opts, "subkeyvalue", 11, TRUE)) /* allow multiple */ duplicate_opt_detection(opts, 1); /* 1 means compound opts */ /* special boolean options */ @@ -1062,6 +1079,35 @@ return; } + fullname = "number_pad"; + if (match_optname(opts, fullname, 10, TRUE)) { + boolean compat = (strlen(opts) <= 10); + number_pad(iflags.num_pad ? 1 : 0); + op = string_for_opt(opts, (compat || !initial)); + if (!op) { + if (compat || negated || initial) { + /* for backwards compatibility, "number_pad" without a + value is a synonym for number_pad:1 */ + iflags.num_pad = !negated; + if (iflags.num_pad) iflags.num_pad_mode = 0; + } + return; + } + if (negated) { + bad_negation("number_pad", TRUE); + return; + } + if (*op == '1' || *op == '2') { + iflags.num_pad = 1; + if (*op == '2') iflags.num_pad_mode = 1; + else iflags.num_pad_mode = 0; + } else if (*op == '0') { + iflags.num_pad = 0; + iflags.num_pad_mode = 0; + } else badoption(opts); + return; + } + fullname = "runmode"; if (match_optname(opts, fullname, 4, TRUE)) { if (negated) { @@ -1663,29 +1722,28 @@ * string as a prefix to get the desired behaviour. * * For backward compatibility, no prefix is required, - * and the presence of a i,a,g,v, or c without a - * prefix sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT; + * and the presence of a i,a,g,v, or c without a prefix + * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT. */ boolean badopt = FALSE; int idx, prefix_val; - if (!(op = string_for_opt(opts, TRUE))) { - /* for backwards compatibility, "disclose" without a - * value means all (was inventory and attributes, - * the only things available then), but negated - * it means "none" - * (note "none" contains none of "iavkgc") - */ - for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++) { - if (negated) - flags.end_disclose[num] = DISCLOSE_NO_WITHOUT_PROMPT; - else flags.end_disclose[num] = DISCLOSE_PROMPT_DEFAULT_YES; - } + + op = string_for_opt(opts, TRUE); + if (op && negated) { + bad_negation("disclose", TRUE); return; } - if (negated) { - bad_negation("disclose", TRUE); + /* "disclose" without a value means "all with prompting" + and negated means "none without prompting" */ + if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) { + if (op && !strcmpi(op, "none")) negated = TRUE; + for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++) + flags.end_disclose[num] = negated ? + DISCLOSE_NO_WITHOUT_PROMPT : + DISCLOSE_PROMPT_DEFAULT_YES; return; } + num = 0; prefix_val = -1; while (*op && num < sizeof flags.end_disclose - 1) { @@ -1930,7 +1999,6 @@ } else if (negated) bad_negation(fullname, TRUE); return; } - fullname = "windowtype"; if (match_optname(opts, fullname, 3, TRUE)) { if (negated) { @@ -2104,9 +2172,6 @@ else lan_mail_finish(); } #endif - else if ((boolopt[i].addr) == &iflags.num_pad) - number_pad(iflags.num_pad ? 1 : 0); - else if ((boolopt[i].addr) == &flags.lit_corridor) { /* * All corridor squares seen via night vision or @@ -2296,6 +2361,8 @@ #endif if (is_wc_option(boolopt[i].name) && !wc_supported(boolopt[i].name)) continue; + if (is_wc2_option(boolopt[i].name) && + !wc2_supported(boolopt[i].name)) continue; any.a_int = (pass == 0) ? 0 : i + 1; if (!iflags.menu_tab_sep) Sprintf(buf, "%s%-13s [%s]", @@ -2347,6 +2414,9 @@ else if (is_wc_option(compopt[i].name) && !wc_supported(compopt[i].name)) continue; + else if (is_wc2_option(compopt[i].name) && + !wc2_supported(compopt[i].name)) + continue; else doset_add_menu(tmpwin, compopt[i].name, (pass == DISP_IN_GAME) ? 0 : indexoffset); @@ -2374,7 +2444,8 @@ Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "", boolopt[opt_indx].name); parseoptions(buf, setinitial, fromfile); - if (wc_supported(boolopt[opt_indx].name)) + if (wc_supported(boolopt[opt_indx].name) || + wc2_supported(boolopt[opt_indx].name)) preference_update(boolopt[opt_indx].name); } else { /* compound option */ @@ -2390,7 +2461,8 @@ /* pass the buck */ parseoptions(buf, setinitial, fromfile); } - if (wc_supported(compopt[opt_indx].name)) + if (wc_supported(compopt[opt_indx].name) || + wc2_supported(compopt[opt_indx].name)) preference_update(compopt[opt_indx].name); } } @@ -2415,8 +2487,8 @@ char buf[BUFSZ]; boolean retval = FALSE; - /* Special handling of menustyle, pickup_burden, and pickup_types, - disclose, runmode, and msg_window options. */ + /* Special handling of menustyle, pickup_burden, pickup_types, + disclose, runmode, msg_window, and number_pad options. */ if (!strcmp("menustyle", optname)) { const char *style_name; menu_item *style_pick = (menu_item *)0; @@ -2600,6 +2672,40 @@ destroy_nhwindow(tmpwin); retval = TRUE; } + else if (!strcmp("number_pad", optname)) { + static const char *npchoices[3] = + {"0 (off)", "1 (on)", "2 (on, DOS compatible)"}; + char *npletters = "abc"; + menu_item *mode_pick = (menu_item *)0; + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + for (i = 0; i < SIZE(npchoices); i++) { + any.a_int = i + 1; + add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0, + ATR_NONE, npchoices[i], MENU_UNSELECTED); + } + end_menu(tmpwin, "Select number_pad mode:"); + if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) { + int mode = mode_pick->item.a_int - 1; + switch(mode) { + case 2: + iflags.num_pad = 1; + iflags.num_pad_mode = 1; + break; + case 1: + iflags.num_pad = 1; + iflags.num_pad_mode = 0; + break; + case 0: + default: + iflags.num_pad = 0; + iflags.num_pad_mode = 0; + } + free((genericptr_t)mode_pick); + } + destroy_nhwindow(tmpwin); + retval = TRUE; + } return retval; } @@ -2744,6 +2855,10 @@ #endif else if (!strcmp(optname, "name")) Sprintf(buf, "%s", plname); + else if (!strcmp(optname, "number_pad")) + Sprintf(buf, "%s", + (!iflags.num_pad) ? "0=off" : + (iflags.num_pad_mode) ? "2=on, DOS compatible" : "1=on"); else if (!strcmp(optname, "objects")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "packorder")) { @@ -3197,6 +3312,13 @@ {(char *)0, 0L} }; +struct wc_Opt wc2_options[] = { + {"fullscreen", WC2_FULLSCREEN}, + {"softkeyboard", WC2_SOFTKEYBOARD}, + {"wraptext", WC2_WRAPTEXT}, + {(char *)0, 0L} +}; + /* * If a port wants to change or ensure that the @@ -3245,7 +3367,7 @@ { int k = 0; if (status < SET_IN_FILE || status > SET_IN_GAME) { - impossible("set_option_mod_status: status out of range %d.", + impossible("set_wc_option_mod_status: status out of range %d.", status); return; } @@ -3284,6 +3406,63 @@ return FALSE; } + +/* + * You can set several wc2_options in one call to + * set_wc2_option_mod_status() by setting + * the appropriate bits for each option that you + * are setting in the optmask argument + * prior to calling. + * example: set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, SET_IN_FILE); + */ + +void +set_wc2_option_mod_status(optmask, status) +unsigned long optmask; +int status; +{ + int k = 0; + if (status < SET_IN_FILE || status > SET_IN_GAME) { + impossible("set_wc2_option_mod_status: status out of range %d.", + status); + return; + } + while (wc2_options[k].wc_name) { + if (optmask & wc2_options[k].wc_bit) { + set_option_mod_status(wc2_options[k].wc_name, status); + } + k++; + } +} + +STATIC_OVL boolean +is_wc2_option(optnam) +const char *optnam; +{ + int k = 0; + while (wc2_options[k].wc_name) { + if (strcmp(wc2_options[k].wc_name, optnam) == 0) + return TRUE; + k++; + } + return FALSE; +} + +STATIC_OVL boolean +wc2_supported(optnam) +const char *optnam; +{ + int k = 0; + while (wc2_options[k].wc_name) { + if (!strcmp(wc2_options[k].wc_name, optnam) && + (windowprocs.wincap2 & wc2_options[k].wc_bit)) + return TRUE; + k++; + } + return FALSE; +} + + STATIC_OVL void wc_set_font_name(wtype, fontname) int wtype; diff -Naurd ../nethack-3.4.1/src/pager.c ./src/pager.c --- ../nethack-3.4.1/src/pager.c Sun Feb 23 14:43:29 2003 +++ ./src/pager.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)pager.c 3.4 2002/12/18 */ +/* SCCS Id: @(#)pager.c 3.4 2003/08/13 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -153,10 +153,9 @@ /* 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); - } + tt == SPIKED_PIT || tt == WEB) + Sprintf(eos(buf), ", trapped in %s", + an(defsyms[trap_to_defsym(tt)].explanation)); } { @@ -350,12 +349,13 @@ if (*dbase_str) { /* adjust the input to remove "named " and convert to lower case */ char *alt = 0; /* alternate description */ + if ((ep = strstri(dbase_str, " named ")) != 0) alt = ep + 7; else ep = strstri(dbase_str, " called "); - if (ep) *ep = '\0'; - else if ((ep = strstri(dbase_str, ", ")) != 0) *ep = '\0'; + if (!ep) ep = strstri(dbase_str, ", "); + if (ep && ep > dbase_str) *ep = '\0'; /* * If the object is named, then the name is the alternate description; @@ -674,7 +674,7 @@ } /* Kludge: warning trumps boulders on the display. Reveal the boulder too or player can get confused */ - if (sobj_at(BOULDER, cc.x, cc.y)) + if (from_screen && sobj_at(BOULDER, cc.x, cc.y)) Strcat(out_str, " co-located with a boulder"); break; /* out of for loop*/ } diff -Naurd ../nethack-3.4.1/src/pickup.c ./src/pickup.c --- ../nethack-3.4.1/src/pickup.c Sun Feb 23 14:43:29 2003 +++ ./src/pickup.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)pickup.c 3.4 2003/01/08 */ +/* SCCS Id: @(#)pickup.c 3.4 2003/07/27 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -31,6 +31,8 @@ STATIC_PTR int FDECL(in_container,(struct obj *)); STATIC_PTR int FDECL(ck_bag,(struct obj *)); STATIC_PTR int FDECL(out_container,(struct obj *)); +STATIC_DCL long FDECL(mbag_item_gone, (int,struct obj *)); +STATIC_DCL void FDECL(observe_quantum_cat, (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 *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P)); @@ -463,8 +465,8 @@ pick_list[i].count = count; } else { n = query_objlist("Pick up what?", objchain, - traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT, - &pick_list, PICK_ANY, all_but_uchain); + traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT|FEEL_COCKATRICE, + &pick_list, PICK_ANY, all_but_uchain); } menu_pickup: n_tried = n; @@ -536,7 +538,9 @@ if (!all_of_a_type) { char qbuf[BUFSZ]; - Sprintf(qbuf, "Pick up %s?", doname(obj)); + Sprintf(qbuf, "Pick up %s?", + safe_qbuf("", sizeof("Pick up ?"), doname(obj), + an(simple_typename(obj->otyp)), "something")); switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) { case 'q': goto end_query; /* out 2 levels */ case 'n': continue; @@ -679,7 +683,13 @@ pack = flags.inv_order; do { printed_type_name = FALSE; - for (curr = olist; curr; curr = FOLLOW(curr, qflags)) + for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { + if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE && + will_feel_cockatrice(curr, FALSE)) { + destroy_nhwindow(win); /* stop the menu and revert */ + (void) look_here(0, FALSE); + return 0; + } if ((!(qflags & INVORDER_SORT) || curr->oclass == *pack) && (*allow)(curr)) { @@ -697,6 +707,7 @@ def_oc_syms[(int)objects[curr->otyp].oc_class], ATR_NONE, doname(curr), MENU_UNSELECTED); } + } pack++; } while (qflags & INVORDER_SORT && *pack); @@ -1122,10 +1133,13 @@ long savequan = obj->quan; obj->quan = *cnt_p; - Sprintf(qbuf, "%s %s. Continue?", + Strcpy(qbuf, (next_encumbr > HVY_ENCUMBER) ? overloadmsg : (next_encumbr > MOD_ENCUMBER) ? nearloadmsg : - moderateloadmsg, doname(obj)); + moderateloadmsg); + Sprintf(eos(qbuf), " %s. Continue?", + safe_qbuf(qbuf, sizeof(" . Continue?"), + doname(obj), an(simple_typename(obj->otyp)), "something")); obj->quan = savequan; switch (ynq(qbuf)) { case 'q': result = -1; break; @@ -1142,6 +1156,32 @@ return result; } +/* To prevent qbuf overflow in prompts use planA only + * if it fits, or planB if PlanA doesn't fit, + * finally using the fallback as a last resort. + * last_restort is expected to be very short. + */ +const char * +safe_qbuf(qbuf, padlength, planA, planB, last_resort) +const char *qbuf, *planA, *planB, *last_resort; +unsigned padlength; +{ + /* convert size_t (or int for ancient systems) to ordinary unsigned */ + unsigned len_qbuf = (unsigned)strlen(qbuf), + len_planA = (unsigned)strlen(planA), + len_planB = (unsigned)strlen(planB), + len_lastR = (unsigned)strlen(last_resort); + unsigned textleft = QBUFSZ - (len_qbuf + padlength); + + if (len_lastR >= textleft) { + impossible("safe_qbuf: last_resort too large at %u characters.", + len_lastR); + return ""; + } + return (len_planA < textleft) ? planA : + (len_planB < textleft) ? planB : last_resort; +} + /* * Pick up of obj from the ground and add it to the hero's inventory. * Returns -1 if caller should break out of its loop, 0 if nothing picked @@ -1275,8 +1315,8 @@ } /* - * Do the actual work of picking otmp from the floor and putting - * it in the hero's inventory. Take care of billing. Return a + * Do the actual work of picking otmp from the floor or monster's interior + * and putting it in the hero's inventory. Take care of billing. Return a * pointer to the object where otmp ends up. This may be different * from otmp because of merging. * @@ -1287,7 +1327,7 @@ struct obj *otmp; { obj_extract_self(otmp); - if (otmp != uball && costly_spot(otmp->ox, otmp->oy)) { + if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) { char saveushops[5], fakeshop[2]; /* addtobill cares about your location rather than the object's; @@ -1306,7 +1346,7 @@ } if (otmp->no_charge) /* only applies to objects outside invent */ otmp->no_charge = 0; - if (Invisible) newsym(otmp->ox, otmp->oy); + newsym(otmp->ox, otmp->oy); return addinv(otmp); /* might merge it with other objects */ } @@ -1392,6 +1432,10 @@ } else if (nolimbs(youmonst.data)) { pline("Without limbs, you cannot loot anything."); return FALSE; + } else if (!freehand()) { + pline("Without a free %s, you cannot loot anything.", + body_part(HAND)); + return FALSE; } return TRUE; } @@ -1445,7 +1489,10 @@ nobj = cobj->nexthere; if (Is_container(cobj)) { - Sprintf(qbuf, "There is %s here, loot it?", doname(cobj)); + Sprintf(qbuf, "There is %s here, loot it?", + safe_qbuf("", sizeof("There is here, loot it?"), + doname(cobj), an(simple_typename(cobj->otyp)), + "a container")); c = ynq(qbuf); if (c == 'q') return (timepassed); if (c == 'n') continue; @@ -1772,8 +1819,7 @@ sellobj_state(SELL_NORMAL); } } - if (Icebox && obj->otyp != OIL_LAMP && obj->otyp != BRASS_LANTERN - && !Is_candle(obj)) { + if (Icebox && !age_is_relative(obj)) { obj->age = monstermoves - obj->age; /* actual age */ /* stop any corpse timeouts when frozen */ if (obj->otyp == CORPSE && obj->timed) { @@ -1783,7 +1829,10 @@ if (rot_alarm) obj->norevive = 1; } } else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) { - You("are blasted by a magical explosion!"); + /* explicitly mention what item is triggering the explosion */ + pline( + "As you put %s inside, you are blasted by a magical explosion!", + doname(obj)); /* did not actually insert obj yet */ if (was_unpaid) addtobill(obj, FALSE, FALSE, TRUE); obfree(obj, (struct obj *)0); @@ -1803,6 +1852,9 @@ Strcpy(buf, the(xname(current_container))); You("put %s into %s.", doname(obj), buf); + /* gold in container always needs to be added to credit */ + if (floor_container && obj->oclass == COIN_CLASS) + sellobj(obj, current_container->ox, current_container->oy); (void) add_to_container(current_container, obj); current_container->owt = weight(current_container); } @@ -1868,8 +1920,7 @@ obj_extract_self(obj); current_container->owt = weight(current_container); - if (Icebox && obj->otyp != OIL_LAMP && obj->otyp != BRASS_LANTERN - && !Is_candle(obj)) { + if (Icebox && !age_is_relative(obj)) { obj->age = monstermoves - obj->age; /* actual age */ if (obj->otyp == CORPSE) start_corpse_timeout(obj); @@ -1902,6 +1953,70 @@ return 1; } +/* an object inside a cursed bag of holding is being destroyed */ +STATIC_OVL long +mbag_item_gone(held, item) +int held; +struct obj *item; +{ + struct monst *shkp; + long loss = 0L; + + if (item->dknown) + pline("%s %s vanished!", Doname2(item), otense(item, "have")); + else + You("%s %s disappear!", Blind ? "notice" : "see", doname(item)); + + if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) { + if (held ? (boolean) item->unpaid : costly_spot(u.ux, u.uy)) + loss = stolen_value(item, u.ux, u.uy, + (boolean)shkp->mpeaceful, TRUE); + } + obfree(item, (struct obj *) 0); + return loss; +} + +STATIC_OVL void +observe_quantum_cat(box) +struct obj *box; +{ + static NEARDATA const char sc[] = "Schroedinger's Cat"; + struct obj *deadcat; + struct monst *livecat; + xchar ox, oy; + + box->spe = 0; /* box->owt will be updated below */ + if (get_obj_location(box, &ox, &oy, 0)) + box->ox = ox, box->oy = oy; /* in case it's being carried */ + + /* this isn't really right, since any form of observation + (telepathic or monster/object/food detection) ought to + force the determination of alive vs dead state; but basing + it just on opening the box is much simpler to cope with */ + livecat = rn2(2) ? makemon(&mons[PM_HOUSECAT], + box->ox, box->oy, NO_MINVENT) : 0; + if (livecat) { + livecat->mpeaceful = 1; + set_malign(livecat); + if (!canspotmon(livecat)) + You("think %s brushed your %s.", something, body_part(FOOT)); + else + pline("%s inside the box is still alive!", Monnam(livecat)); + (void) christen_monst(livecat, sc); + } else { + deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT], + box->ox, box->oy, sc); + if (deadcat) { + obj_extract_self(deadcat); + (void) add_to_container(box, deadcat); + } + pline_The("%s inside the box is dead!", + Hallucination ? rndmonnam() : "housecat"); + } + box->owt = weight(box); + return; +} + #undef Icebox int @@ -1913,12 +2028,12 @@ #ifndef GOLDOBJ struct obj *u_gold = (struct obj *)0; #endif - struct monst *shkp; - boolean one_by_one, allflag, loot_out = FALSE, loot_in = FALSE; + boolean one_by_one, allflag, quantum_cat = FALSE, + loot_out = FALSE, loot_in = FALSE; char select[MAXOCLASSES+1]; char qbuf[BUFSZ], emptymsg[BUFSZ], pbuf[QBUFSZ]; long loss = 0L; - int cnt = 0, used = 0, lcnt = 0, + int cnt = 0, used = 0, menu_on_request; emptymsg[0] = '\0'; @@ -1946,80 +2061,35 @@ current_container = obj; /* for use by in/out_container */ if (obj->spe == 1) { - static NEARDATA const char sc[] = "Schroedinger's Cat"; - struct obj *ocat; - struct monst *cat; - - obj->spe = 0; /* obj->owt will be updated below */ - /* this isn't really right, since any form of observation - (telepathic or monster/object/food detection) ought to - force the determination of alive vs dead state; but basing - it just on opening the box is much simpler to cope with */ - cat = rn2(2) ? makemon(&mons[PM_HOUSECAT], - obj->ox, obj->oy, NO_MINVENT) : 0; - if (cat) { - cat->mpeaceful = 1; - set_malign(cat); - if (Blind) - You("think %s brushed your %s.", something, - body_part(FOOT)); - else - pline("%s inside the box is still alive!", Monnam(cat)); - (void) christen_monst(cat, sc); - } else { - ocat = mk_named_object(CORPSE, &mons[PM_HOUSECAT], - obj->ox, obj->oy, sc); - if (ocat) { - obj_extract_self(ocat); - (void) add_to_container(obj, ocat); - /* weight handled below */ - } - pline_The("%s inside the box is dead!", - Hallucination ? rndmonnam() : "housecat"); - } + observe_quantum_cat(obj); used = 1; + quantum_cat = TRUE; /* for adjusting "it's empty" message */ } /* Count the number of contained objects. Sometimes toss objects if */ /* a cursed magic bag. */ for (curr = obj->cobj; curr; curr = otmp) { otmp = curr->nobj; if (Is_mbag(obj) && obj->cursed && !rn2(13)) { - if (curr->dknown) - pline("%s to have vanished!", The(aobjnam(curr,"seem"))); - else - You("%s %s disappear.", Blind ? "notice" : "see", - doname(curr)); obj_extract_self(curr); - if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) { - if(held) { - if(curr->unpaid) - loss += stolen_value(curr, u.ux, u.uy, - (boolean)shkp->mpeaceful, TRUE); - lcnt++; - } else if(costly_spot(u.ux, u.uy)) { - loss += stolen_value(curr, u.ux, u.uy, - (boolean)shkp->mpeaceful, TRUE); - lcnt++; - } - } - /* obfree() will free all contained objects */ - obfree(curr, (struct obj *) 0); + loss += mbag_item_gone(held, curr); used = 1; } else { cnt++; } } - if (lcnt && loss) - You("owe %ld %s for lost item%s.", - loss, currency(loss), lcnt > 1 ? "s" : ""); + if (loss) /* magic bag lost some shop goods */ + You("owe %ld %s for lost merchandise.", loss, currency(loss)); + obj->owt = weight(obj); /* in case any items were lost */ - obj->owt = weight(obj); + if (!cnt) + Sprintf(emptymsg, "%s is %sempty.", Yname2(obj), + quantum_cat ? "now " : ""); - 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)); + Strcpy(qbuf, "Do you want to take something out of "); + Sprintf(eos(qbuf), "%s?", + safe_qbuf(qbuf, 1, yname(obj), ysimple_name(obj), "it")); if (flags.menu_style != MENU_TRADITIONAL) { if (flags.menu_style == MENU_FULL) { int t; diff -Naurd ../nethack-3.4.1/src/polyself.c ./src/polyself.c --- ../nethack-3.4.1/src/polyself.c Sun Feb 23 14:43:29 2003 +++ ./src/polyself.c Mon Sep 1 14:33:32 2003 @@ -34,7 +34,7 @@ { boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow, was_mimicking = (youmonst.m_ap_type == M_AP_OBJECT); - + boolean could_pass_walls = Passes_walls; boolean was_blind = !!Blind; if (Upolyd) { @@ -54,17 +54,9 @@ find_ac(); if (was_mimicking) { if (multi < 0) unmul(""); - } else { - /* - * Clear any in-progress imitations -- the case where not a - * mimic is handled above. - * - * Except, this is not complete if the hero ever gets the - * chance to imitate anything, then s/he may be mimicing - * gold, but not the way its done for eating a mimic. - */ youmonst.m_ap_type = M_AP_NOTHING; } + newsym(u.ux,u.uy); You(fmt, arg); @@ -87,6 +79,11 @@ if (u.twoweap && !could_twoweap(youmonst.data)) untwoweapon(); + if (u.utraptype == TT_PIT) { + if (could_pass_walls) { /* player forms cannot pass walls */ + u.utrap = rn1(6,2); + } + } if (was_blind && !Blind) { /* reverting from eyeless */ Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ @@ -331,6 +328,7 @@ { boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow, was_blind = !!Blind, dochange = FALSE; + boolean could_pass_walls = Passes_walls; int mlvl; if (mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */ @@ -462,6 +460,13 @@ else u.uundetected = 0; + if (u.utraptype == TT_PIT) { + if (could_pass_walls && !Passes_walls) { + u.utrap = rn1(6,2); + } else if (!could_pass_walls && Passes_walls) { + u.utrap = 0; + } + } if (was_blind && !Blind) { /* previous form was eyeless */ Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ @@ -619,7 +624,7 @@ /* Future possiblities: This could damage/destroy helmet */ Sprintf(hornbuf, "horn%s", plur(num_horns(youmonst.data))); - Your("%s through %s %s.", vtense(hornbuf, "pierce"), + Your("%s %s through %s %s.", hornbuf, vtense(hornbuf, "pierce"), shk_your(yourbuf, otmp), xname(otmp)); } else { if (donning(otmp)) cancel_don(); @@ -835,11 +840,11 @@ case SPIKED_PIT: You("spin a web, covering up the pit."); deltrap(ttmp); bury_objs(u.ux, u.uy); - if (Invisible) newsym(u.ux, u.uy); + newsym(u.ux, u.uy); return(1); case SQKY_BOARD: pline_The("squeaky board is muffled."); deltrap(ttmp); - if (Invisible) newsym(u.ux, u.uy); + newsym(u.ux, u.uy); return(1); case TELEP_TRAP: case LEVEL_TELEP: @@ -853,12 +858,12 @@ You("web over the %s.", (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole"); deltrap(ttmp); - if (Invisible) newsym(u.ux, u.uy); + newsym(u.ux, u.uy); return 1; case ROLLING_BOULDER_TRAP: You("spin a web, jamming the trigger."); deltrap(ttmp); - if (Invisible) newsym(u.ux, u.uy); + newsym(u.ux, u.uy); return(1); case ARROW_TRAP: case DART_TRAP: @@ -877,13 +882,20 @@ default: impossible("Webbing over trap type %d?", ttmp->ttyp); return(0); + } + else if (On_stairs(u.ux, u.uy)) { + /* cop out: don't let them hide the stairs */ + Your("web fails to impede access to the %s.", + (levl[u.ux][u.uy].typ == STAIRS) ? "stairs" : "ladder"); + return(1); + } ttmp = maketrap(u.ux, u.uy, WEB); if (ttmp) { ttmp->tseen = 1; ttmp->madeby_u = 1; } - if (Invisible) newsym(u.ux, u.uy); + newsym(u.ux, u.uy); return(1); } diff -Naurd ../nethack-3.4.1/src/pray.c ./src/pray.c --- ../nethack-3.4.1/src/pray.c Sun Feb 23 14:43:29 2003 +++ ./src/pray.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)pray.c 3.4 2002/10/06 */ +/* SCCS Id: @(#)pray.c 3.4 2003/03/23 */ /* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -70,33 +70,37 @@ * order to have the values be meaningful. */ -#define TROUBLE_STONED 12 -#define TROUBLE_SLIMED 11 -#define TROUBLE_STRANGLED 10 -#define TROUBLE_LAVA 9 -#define TROUBLE_SICK 8 -#define TROUBLE_STARVING 7 -#define TROUBLE_HIT 6 -#define TROUBLE_LYCANTHROPE 5 -#define TROUBLE_COLLAPSING 4 -#define TROUBLE_STUCK_IN_WALL 3 -#define TROUBLE_CURSED_LEVITATION 2 -#define TROUBLE_CURSED_BLINDFOLD 1 +#define TROUBLE_STONED 13 +#define TROUBLE_SLIMED 12 +#define TROUBLE_STRANGLED 11 +#define TROUBLE_LAVA 10 +#define TROUBLE_SICK 9 +#define TROUBLE_STARVING 8 +#define TROUBLE_HIT 7 +#define TROUBLE_LYCANTHROPE 6 +#define TROUBLE_COLLAPSING 5 +#define TROUBLE_STUCK_IN_WALL 4 +#define TROUBLE_CURSED_LEVITATION 3 +#define TROUBLE_UNUSEABLE_HANDS 2 +#define TROUBLE_CURSED_BLINDFOLD 1 -#define TROUBLE_PUNISHED (-1) -#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) +#define TROUBLE_PUNISHED (-1) +#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. */ + unintentional shape changes from the other kind. Oh well. + 3.4.2: make an exception if polymorphed into a form which lacks + hands; that's a case where the ramifications override this doubt. + */ /* Return 0 if nothing particular seems wrong, positive numbers for serious trouble, and negative numbers for comparative annoyances. This @@ -115,9 +119,7 @@ STATIC_OVL int in_trouble() { -#ifdef STEED - register struct obj *otmp; -#endif + struct obj *otmp; int i, j, count=0; /* Borrowed from eat.c */ @@ -158,6 +160,15 @@ stuck_ring(uleft, RIN_LEVITATION) || stuck_ring(uright, RIN_LEVITATION)) return(TROUBLE_CURSED_LEVITATION); + if (nohands(youmonst.data) || !freehand()) { + /* for bag/box access [cf use_container()]... + make sure it's a case that we know how to handle; + otherwise "fix all troubles" would get stuck in a loop */ + if (welded(uwep)) return TROUBLE_UNUSEABLE_HANDS; + if (Upolyd && nohands(youmonst.data) && (!Unchanging || + ((otmp = unchanger()) != 0 && otmp->cursed))) + return TROUBLE_UNUSEABLE_HANDS; + } if(Blindfolded && ublindf->cursed) return(TROUBLE_CURSED_BLINDFOLD); /* @@ -202,9 +213,8 @@ 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)))) { + with taking off a ring or putting on a shield */ + if (welded(uwep) && (uright || bimanual(uwep))) { /* weapon */ otmp = uwep; /* gloves come next, due to rings */ } else if (uarmg && uarmg->cursed) { /* gloves */ @@ -335,6 +345,23 @@ if (otmp == uright) what = rightglow; } goto decurse; + case TROUBLE_UNUSEABLE_HANDS: + if (welded(uwep)) { + otmp = uwep; + goto decurse; + } + if (Upolyd && nohands(youmonst.data)) { + if (!Unchanging) { + Your("shape becomes uncertain."); + rehumanize(); /* "You return to {normal} form." */ + } else if ((otmp = unchanger()) != 0 && otmp->cursed) { + /* otmp is an amulet of unchanging */ + goto decurse; + } + } + if (nohands(youmonst.data) || !freehand()) + impossible("fix_worst_trouble: couldn't cure hands."); + break; case TROUBLE_CURSED_BLINDFOLD: otmp = ublindf; goto decurse; @@ -1164,7 +1191,7 @@ 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); + newsym(u.ux, u.uy); angry_priest(); demonless_msg = "cloud dissipates"; } else { diff -Naurd ../nethack-3.4.1/src/restore.c ./src/restore.c --- ../nethack-3.4.1/src/restore.c Sun Feb 23 14:43:29 2003 +++ ./src/restore.c Mon Sep 1 14:33:32 2003 @@ -217,11 +217,7 @@ * to new player's clock. Assumption: new player arrived * immediately after old player died. */ - if (ghostly && !frozen - && otmp->otyp != OIL_LAMP - && otmp->otyp != BRASS_LANTERN - && otmp->otyp != CANDELABRUM_OF_INVOCATION - && !Is_candle(otmp)) + if (ghostly && !frozen && !age_is_relative(otmp)) otmp->age = monstermoves - omoves + otmp->age; /* get contents of a container or statue */ @@ -977,6 +973,7 @@ struct monst *mtmp = (struct monst *)otmp->oextra; mtmp->m_id = 0; + mtmp->mpeaceful = mtmp->mtame = 0; /* pet's owner died! */ } if (ghostly && otmp->oattached == OATTACHED_M_ID) { (void) memcpy((genericptr_t)&oldid, (genericptr_t)otmp->oextra, diff -Naurd ../nethack-3.4.1/src/role.c ./src/role.c --- ../nethack-3.4.1/src/role.c Sun Feb 23 14:43:29 2003 +++ ./src/role.c Mon Sep 1 14:33:32 2003 @@ -1368,13 +1368,15 @@ if (!validrace(flags.initrole, flags.initrace)) flags.initrace = randrace(flags.initrole); - /* Check for a valid gender. Try flags.igend first. */ + /* Check for a valid gender. If new game, check both initgend + * and female. On restore, assume flags.female is correct. */ + if (flags.pantheon == -1) { /* new game */ + if (!validgend(flags.initrole, flags.initrace, flags.female)) + flags.female = !flags.female; + } if (!validgend(flags.initrole, flags.initrace, flags.initgend)) - /* Use flags.female second. Note that there is no way - * to check for an unspecified gender. - */ + /* Note that there is no way to check for an unspecified gender. */ flags.initgend = flags.female; - /* Don't change flags.female; this may be a restore */ /* Check for a valid alignment */ if (!validalign(flags.initrole, flags.initrace, flags.initalign)) diff -Naurd ../nethack-3.4.1/src/shk.c ./src/shk.c --- ../nethack-3.4.1/src/shk.c Sun Feb 23 14:43:30 2003 +++ ./src/shk.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)shk.c 3.4 2003/01/08 */ +/* SCCS Id: @(#)shk.c 3.4 2003/08/18 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -56,6 +56,7 @@ STATIC_DCL void FDECL(set_repo_loc, (struct eshk *)); STATIC_DCL boolean NDECL(angry_shk_exists); STATIC_DCL void FDECL(rile_shk, (struct monst *)); +STATIC_DCL void FDECL(rouse_shk, (struct monst *,BOOLEAN_P)); STATIC_DCL void FDECL(remove_damage, (struct monst *, BOOLEAN_P)); STATIC_DCL void FDECL(sub_one_frombill, (struct obj *, struct monst *)); STATIC_DCL void FDECL(add_one_tobill, (struct obj *, BOOLEAN_P)); @@ -463,7 +464,7 @@ } } -/* shop merchandize has been taken; pay for it with any credit available; +/* shop merchandise 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) @@ -950,6 +951,23 @@ } } +/* wakeup and/or unparalyze shopkeeper */ +STATIC_OVL void +rouse_shk(shkp, verbosely) +struct monst *shkp; +boolean verbosely; +{ + if (!shkp->mcanmove) { + /* greed induced recovery... */ + if (verbosely && canspotmon(shkp)) + pline("%s %s.", Monnam(shkp), + shkp->msleeping ? "wakes up" : "can move again"); + shkp->msleeping = 0; + shkp->mfrozen = 0; + shkp->mcanmove = 1; + } +} + void make_happy_shk(shkp, silentkops) register struct monst *shkp; @@ -1170,15 +1188,18 @@ return(0); } proceed: + eshkp = ESHK(shkp); + ltmp = eshkp->robbed; - if (shkp->msleeping || !shkp->mcanmove) { + /* wake sleeping shk when someone who owes money offers payment */ + if (ltmp || eshkp->billct || eshkp->debit) + rouse_shk(shkp, TRUE); + + if (!shkp->mcanmove) { /* still asleep or paralyzed */ pline("%s %s.", Monnam(shkp), rn2(2) ? "seems to be napping" : "doesn't respond"); return 0; } - eshkp = ESHK(shkp); - - ltmp = eshkp->robbed; if(shkp != resident && NOTANGRY(shkp)) { #ifdef GOLDOBJ @@ -1623,14 +1644,15 @@ /* the simplifying principle is that first-come */ /* already took everything you had. */ - if(numsk > 1) { - if(cansee(shkp->mx, shkp->my) && croaked) - pline("%s %slooks at your corpse%s%s", Monnam(shkp), - (shkp->msleeping || !shkp->mcanmove) ? - "wakes up, " : "", - !rn2(2) ? (shkp->female ? ", shakes her head," : - ", shakes his head,") : "", - !inhishop(shkp) ? " and disappears. " : " and sighs."); + if (numsk > 1) { + if (cansee(shkp->mx, shkp->my && croaked)) + pline("%s %slooks at your corpse%s and %s.", + Monnam(shkp), + !shkp->mcanmove ? "wakes up, " : "", + !rn2(2) ? (shkp->female ? ", shakes her head," : + ", shakes his head,") : "", + !inhishop(shkp) ? "disappears" : "sighs"); + rouse_shk(shkp, FALSE); /* wake shk for bones */ taken = (roomno == eshkp->shoproom); goto skip; } @@ -1662,7 +1684,7 @@ umoney = money_cnt(invent); #endif takes[0] = '\0'; - if (shkp->msleeping || !shkp->mcanmove) + if (!shkp->mcanmove) Strcat(takes, "wakes up and "); if (distu(shkp->mx, shkp->my) > 2) Strcat(takes, "comes and "); @@ -1707,7 +1729,7 @@ } skip: /* in case we create bones */ - shkp->msleeping = 0; + rouse_shk(shkp, FALSE); /* wake up */ if (!inhishop(shkp)) home_shk(shkp, FALSE); } @@ -1754,6 +1776,8 @@ #if 0 /* don't bother */ if (ox == 0 && oy == 0) impossible("finish_paybill: no location"); #endif + /* normally done by savebones(), but that's too late in this case */ + unleash_all(); /* transfer all of the character's inventory to the shop floor */ while ((otmp = invent) != 0) { otmp->owornmask = 0L; /* perhaps we should call setnotworn? */ @@ -2441,7 +2465,13 @@ if(peaceful) { boolean credit_use = !!ESHK(shkp)->credit; value = check_credit(value, shkp); - ESHK(shkp)->debit += value; + /* 'peaceful' affects general treatment, but doesn't affect + * the fact that other code expects that all charges after the + * shopkeeper is angry are included in robbed, not debit */ + if (ANGRY(shkp)) + ESHK(shkp)->robbed += value; + else + ESHK(shkp)->debit += value; if(!silent) { const char *still = ""; @@ -2557,22 +2587,7 @@ } /* you dropped something of your own - probably want to sell it */ - if (shkp->msleeping || !shkp->mcanmove) { - if (container) - dropped_container(obj, shkp, TRUE); - if (!obj->unpaid) - obj->no_charge = 1; - if (!shkp->mcanmove) { - if(ANGRY(shkp) && !rn2(4)) - pline("%s utters a curse.", Monnam(shkp)); - else pline("%s is indisposed.", Monnam(shkp)); - } else if(!rn2(3)) { - pline("%s snores indifferently.", Monnam(shkp)); - } - subfrombill(obj, shkp); - return; - } - + rouse_shk(shkp, TRUE); /* wake up sleeping or paralyzed shk */ eshkp = ESHK(shkp); if (ANGRY(shkp)) { /* they become shop-objects, no pay */ @@ -3843,7 +3858,8 @@ if (otmp->spe > 1) tmp /= 4L; } else if (otmp->oclass == SPBOOK_CLASS) { tmp -= tmp / 5L; - } else if (otmp->otyp == CAN_OF_GREASE + } else if (otmp->otyp == CAN_OF_GREASE || + otmp->otyp == TINNING_KIT #ifdef TOURIST || otmp->otyp == EXPENSIVE_CAMERA #endif diff -Naurd ../nethack-3.4.1/src/shknam.c ./src/shknam.c --- ../nethack-3.4.1/src/shknam.c Sun Feb 23 14:43:30 2003 +++ ./src/shknam.c Mon Sep 1 14:33:32 2003 @@ -18,7 +18,9 @@ static const char * const shkliquors[] = { /* Ukraine */ - "Njezjin", "Tsjernigof", "Gomel", "Ossipewsk", "Gorlowka", + "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka", + /* Belarus */ + "Gomel", /* N. Russia */ "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja", "Narodnaja", "Kyzyl", diff -Naurd ../nethack-3.4.1/src/sit.c ./src/sit.c --- ../nethack-3.4.1/src/sit.c Sun Feb 23 14:43:30 2003 +++ ./src/sit.c Mon Sep 1 14:33:32 2003 @@ -68,7 +68,8 @@ if (!(Is_box(obj) || objects[obj->otyp].oc_material == CLOTH)) pline("It's not very comfortable..."); - } else if ((trap = t_at(u.ux, u.uy)) != 0) { + } else if ((trap = t_at(u.ux, u.uy)) != 0 || + (u.utrap && (u.utraptype >= TT_LAVA))) { if (u.utrap) { exercise(A_WIS, FALSE); /* you're getting stuck longer */ diff -Naurd ../nethack-3.4.1/src/sounds.c ./src/sounds.c --- ../nethack-3.4.1/src/sounds.c Sun Feb 23 14:43:30 2003 +++ ./src/sounds.c Mon Sep 1 14:33:32 2003 @@ -435,6 +435,12 @@ if (!flags.soundok) return(0); if (is_silent(ptr)) return(0); + /* Make sure its your role's quest quardian; adjust if not */ + if (ptr->msound == MS_GUARDIAN && ptr != &mons[urole.guardnum]) { + int mndx = monsndx(ptr); + ptr = &mons[genus(mndx,1)]; + } + /* be sure to do this before talking; the monster might teleport away, in * which case we want to check its pre-teleport position */ @@ -561,7 +567,7 @@ mtmp->mtame < 5) pline_msg = "yowls."; else if (moves > EDOG(mtmp)->hungrytime) - pline_msg = "miaos."; + pline_msg = "meows."; else if (EDOG(mtmp)->hungrytime > moves + 1000) pline_msg = "purrs."; else @@ -578,7 +584,7 @@ pline_msg = "squeaks."; break; case MS_SQAWK: - if (mtmp->data == &mons[PM_RAVEN] && !mtmp->mpeaceful) + if (ptr == &mons[PM_RAVEN] && !mtmp->mpeaceful) verbl_msg = "Nevermore!"; else pline_msg = "squawks."; diff -Naurd ../nethack-3.4.1/src/sp_lev.c ./src/sp_lev.c --- ../nethack-3.4.1/src/sp_lev.c Sun Feb 23 14:43:30 2003 +++ ./src/sp_lev.c Mon Sep 1 14:33:32 2003 @@ -2167,6 +2167,11 @@ for(x = xstart; x < xstart+xsize; x++) { levl[x][y].typ = Fgetc(fd); levl[x][y].lit = FALSE; + /* clear out levl: load_common_data may set them */ + levl[x][y].flags = 0; + levl[x][y].horizontal = 0; + levl[x][y].roomno = 0; + levl[x][y].edge = 0; /* * Note: Even though levl[x][y].typ is type schar, * lev_comp.y saves it as type char. Since schar != char @@ -2198,6 +2203,8 @@ has_bounds = TRUE; Map[x][y] = 1; } + if (init_lev.init_present && init_lev.joined) + remove_rooms(xstart, ystart, xstart+xsize, ystart+ysize); } Fread((genericptr_t) &n, 1, sizeof(n), fd); diff -Naurd ../nethack-3.4.1/src/steed.c ./src/steed.c --- ../nethack-3.4.1/src/steed.c Sun Feb 23 14:43:30 2003 +++ ./src/steed.c Mon Sep 1 14:33:32 2003 @@ -12,7 +12,7 @@ S_QUADRUPED, S_UNICORN, S_ANGEL, S_CENTAUR, S_DRAGON, S_JABBERWOCK, '\0' }; -STATIC_DCL boolean FDECL(landing_spot, (coord *, int)); +STATIC_DCL boolean FDECL(landing_spot, (coord *, int, int)); /* caller has decided that hero can't reach something while mounted */ void @@ -84,8 +84,8 @@ You("touch %s.", mon_nam(mtmp)); if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { - Sprintf(kbuf, "attempting to saddle %s", a_monnam(mtmp)); - instapetrify(kbuf); + Sprintf(kbuf, "attempting to saddle %s", an(mtmp->data->mname)); + instapetrify(kbuf); } } if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) { @@ -415,30 +415,38 @@ * Adapted from mail daemon code. */ STATIC_OVL boolean -landing_spot(spot, forceit) +landing_spot(spot, reason, forceit) coord *spot; /* landing position (we fill it in) */ +int reason; int forceit; { - int x, y, distance, min_distance = -1; + int i = 0, x, y, distance, min_distance = -1; boolean found = FALSE; - - for (x = u.ux-1; x <= u.ux+1; x++) - for (y = u.uy-1; y <= u.uy+1; y++) { - if (!isok(x, y) || (x == u.ux && y == u.uy)) continue; + struct trap *t; - if (ACCESSIBLE(levl[x][y].typ) && - !MON_AT(x,y) && !closed_door(x,y)) { - distance = distu(x,y); - if (min_distance < 0 || distance < min_distance || - (distance == min_distance && rn2(2))) { - spot->x = x; - spot->y = y; - min_distance = distance; - found = TRUE; + /* avoid known traps (i == 0), but allow them as a backup */ + if (reason != DISMOUNT_BYCHOICE || Stunned || Confusion || Fumbling) i = 1; + for (; !found && i < 2; ++i) { + for (x = u.ux-1; x <= u.ux+1; x++) + for (y = u.uy-1; y <= u.uy+1; y++) { + if (!isok(x, y) || (x == u.ux && y == u.uy)) continue; + + if (ACCESSIBLE(levl[x][y].typ) && + !MON_AT(x,y) && !closed_door(x,y)) { + distance = distu(x,y); + if (min_distance < 0 || distance < min_distance || + (distance == min_distance && rn2(2))) { + if (i > 0 || (t = t_at(x, y)) == 0 || !t->tseen) { + spot->x = x; + spot->y = y; + min_distance = distance; + found = TRUE; + } + } } } - } - + } + /* If we didn't find a good spot and forceit is on, try enexto(). */ if (forceit && min_distance < 0 && !enexto(spot, u.ux, u.uy, youmonst.data)) @@ -458,7 +466,7 @@ const char *verb = "fall"; boolean repair_leg_damage = TRUE; unsigned save_utrap = u.utrap; - boolean have_spot = landing_spot(&cc,0); + boolean have_spot = landing_spot(&cc,reason,0); mtmp = u.usteed; /* make a copy of steed pointer */ /* Sanity check */ @@ -472,14 +480,14 @@ verb = "are thrown"; case DISMOUNT_FELL: You("%s off of %s!", verb, mon_nam(mtmp)); - if (!have_spot) have_spot = landing_spot(&cc,1); + if (!have_spot) have_spot = landing_spot(&cc,reason,1); losehp(rn1(10,10), "riding accident", KILLED_BY_AN); set_wounded_legs(BOTH_SIDES, (int)HWounded_legs + rn1(5,5)); repair_leg_damage = FALSE; break; case DISMOUNT_POLY: You("can no longer ride %s.", mon_nam(u.usteed)); - if (!have_spot) have_spot = landing_spot(&cc,1); + if (!have_spot) have_spot = landing_spot(&cc,reason,1); break; case DISMOUNT_ENGULFED: /* caller displays message */ diff -Naurd ../nethack-3.4.1/src/teleport.c ./src/teleport.c --- ../nethack-3.4.1/src/teleport.c Sun Feb 23 14:43:30 2003 +++ ./src/teleport.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)teleport.c 3.4 2002/11/20 */ +/* SCCS Id: @(#)teleport.c 3.4 2003/08/11 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -586,7 +586,13 @@ Strcpy(qbuf, "To what level do you want to teleport?"); do { - if (++trycnt == 2) Strcat(qbuf, " [type a number]"); + if (++trycnt == 2) { +#ifdef WIZARD + if (wizard) Strcat(qbuf, " [type a number or ? for a menu]"); + else +#endif + Strcat(qbuf, " [type a number]"); + } getlin(qbuf, buf); if (!strcmp(buf,"\033")) { /* cancelled */ if (Confusion && rnl(5)) { @@ -600,6 +606,11 @@ pline("Oops..."); goto random_levtport; } +#ifdef WIZARD + if (wizard && !strcmp(buf,"?")) { + newlev = print_dungeon(TRUE); + } else +#endif if ((newlev = lev_by_name(buf)) == 0) newlev = atoi(buf); } while (!newlev && !digit(buf[0]) && (buf[0] != '-' || !digit(buf[1])) && @@ -1161,15 +1172,11 @@ int random_teleport_level() { - int nlev, max_depth, min_depth; + int nlev, max_depth, min_depth, + cur_depth = (int)depth(&u.uz); if (!rn2(5) || Is_knox(&u.uz)) - return (int)depth(&u.uz); - - /* Get a random value relative to the current dungeon */ - /* Range is 1 to current+3, current not counting */ - nlev = rnd((int)depth(&u.uz) + 2); - if (nlev >= (int)depth(&u.uz)) nlev++; + return cur_depth; /* What I really want to do is as follows: * -- If in a dungeon that goes down, the new level is to be restricted @@ -1186,10 +1193,20 @@ * above; endgame is handled in the caller due to its different * message ("disoriented"). * --KAA + * 3.4.2: explicitly handle quest here too, to fix the problem of + * monsters sometimes level teleporting out of it into main dungeon. + * Also prevent monsters reaching the Sanctum prior to invocation. */ - min_depth = 1; + min_depth = In_quest(&u.uz) ? dungeons[u.uz.dnum].depth_start : 1; max_depth = dunlevs_in_dungeon(&u.uz) + (dungeons[u.uz.dnum].depth_start - 1); + /* can't reach the Sanctum if the invocation hasn't been performed */ + if (Inhell && !u.uevent.invoked) max_depth -= 1; + + /* Get a random value relative to the current dungeon */ + /* Range is 1 to current+3, current not counting */ + nlev = rn2(cur_depth + 3 - min_depth) + min_depth; + if (nlev >= cur_depth) nlev++; if (nlev > max_depth) { nlev = max_depth; @@ -1198,9 +1215,9 @@ } if (nlev < min_depth) { nlev = min_depth; - if ((int)depth(&u.uz) == min_depth) { - nlev += rnd(3); - if (nlev > max_depth) + if (nlev == cur_depth) { + nlev += rnd(3); + if (nlev > max_depth) nlev = max_depth; } } diff -Naurd ../nethack-3.4.1/src/topten.c ./src/topten.c --- ../nethack-3.4.1/src/topten.c Sun Feb 23 14:43:30 2003 +++ ./src/topten.c Mon Sep 1 14:33:32 2003 @@ -77,7 +77,7 @@ /* must fit with end.c; used in rip.c */ NEARDATA const char * const killed_by_prefix[] = { - "killed by ", "choked on ", "poisoned by ", "", "drowned in ", + "killed by ", "choked on ", "poisoned by ", "died of ", "drowned in ", "burned by ", "dissolved in ", "crushed to death by ", "petrified by ", "turned to slime by ", "killed by ", "", "", "", "", "" }; diff -Naurd ../nethack-3.4.1/src/trap.c ./src/trap.c --- ../nethack-3.4.1/src/trap.c Sun Feb 23 14:43:31 2003 +++ ./src/trap.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)trap.c 3.4 2003/02/10 */ +/* SCCS Id: @(#)trap.c 3.4 2003/05/25 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -26,6 +26,8 @@ STATIC_DCL boolean FDECL(isclearpath,(coord *, int, SCHAR_P, SCHAR_P)); #ifdef STEED STATIC_OVL int FDECL(steedintrap, (struct trap *, struct obj *)); +STATIC_OVL boolean FDECL(keep_saddle_with_steedcorpse, + (unsigned, struct obj *, struct obj *)); #endif #ifndef OVLB @@ -409,7 +411,10 @@ struct monst *mon = 0; struct obj *item; coord cc; - boolean historic = (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && statue->spe); + boolean historic = (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (statue->spe & STATUE_HISTORIC)); + char statuename[BUFSZ]; + + Strcpy(statuename,the(xname(statue))); if (statue->oxlth && statue->oattached == OATTACHED_MONST) { cc.x = x, cc.y = y; @@ -417,18 +422,41 @@ if (mon && mon->mtame && !mon->isminion) wary_dog(mon, TRUE); } else { + /* statue of any golem hit with stone-to-flesh becomes flesh golem */ + if (is_golem(&mons[statue->corpsenm]) && cause == ANIMATE_SPELL) + mptr = &mons[PM_FLESH_GOLEM]; + else + mptr = &mons[statue->corpsenm]; /* * Guard against someone wishing for a statue of a unique monster * (which is allowed in normal play) and then tossing it onto the * [detected or guessed] location of a statue trap. Normally the * uppermost statue is the one which would be activated. */ - mptr = &mons[statue->corpsenm]; - if (mptr->geno & G_UNIQ) { + if ((mptr->geno & G_UNIQ) && cause != ANIMATE_SPELL) { if (fail_reason) *fail_reason = AS_MON_IS_UNIQUE; return (struct monst *)0; } - mon = makemon(mptr, x, y, NO_MINVENT); + if (cause == ANIMATE_SPELL && + ((mptr->geno & G_UNIQ) || mptr->msound == MS_GUARDIAN)) { + /* Statues of quest guardians or unique monsters + * will not stone-to-flesh as the real thing. + */ + mon = makemon(&mons[PM_DOPPELGANGER], x, y, + NO_MINVENT|MM_NOCOUNTBIRTH|MM_ADJACENTOK); + if (mon) { + /* makemon() will set mon->cham to + * CHAM_ORDINARY if hero is wearing + * ring of protection from shape changers + * when makemon() is called, so we have to + * check the field before calling newcham(). + */ + if (mon->cham == CHAM_DOPPELGANGER) + (void) newcham(mon, mptr, FALSE, FALSE); + } + } else + mon = makemon(mptr, x, y, (cause == ANIMATE_SPELL) ? + (NO_MINVENT | MM_ADJACENTOK) : NO_MINVENT); } if (!mon) { @@ -436,6 +464,11 @@ return (struct monst *)0; } + /* allow statues to be of a specific gender */ + if (statue->spe & STATUE_MALE) + mon->female = FALSE; + else if (statue->spe & STATUE_FEMALE) + mon->female = TRUE; /* if statue has been named, give same name to the monster */ if (statue->onamelth) mon = christen_monst(mon, ONAME(statue)); @@ -450,18 +483,26 @@ if (mon->m_ap_type) seemimic(mon); else mon->mundetected = FALSE; if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) { - pline_The("statue %s!", - canspotmon(mon) ? "comes to life" : "disappears"); - if (historic) { + const char *comes_to_life = nonliving(mon->data) ? + "moves" : "comes to life"; + if (cause == ANIMATE_SPELL) + pline("%s %s!", upstart(statuename), + canspotmon(mon) ? comes_to_life : "disappears"); + else + 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 */ + else { /* cause == ANIMATE_NORMAL */ You("find %s posing as a statue.", canspotmon(mon) ? a_monnam(mon) : something); + stop_occupation(); + } /* avoid hiding under nothing */ if (x == u.ux && y == u.uy && Upolyd && hides_under(youmonst.data) && !OBJ_AT(x, y)) @@ -506,6 +547,37 @@ return mtmp; } +#ifdef STEED +STATIC_OVL boolean +keep_saddle_with_steedcorpse(steed_mid, objchn, saddle) +unsigned steed_mid; +struct obj *objchn, *saddle; +{ + if (!saddle) return FALSE; + while(objchn) { + if(objchn->otyp == CORPSE && + objchn->oattached == OATTACHED_MONST && objchn->oxlth) { + struct monst *mtmp = (struct monst *)objchn->oextra; + if (mtmp->m_id == steed_mid) { + /* move saddle */ + xchar x,y; + if (get_obj_location(objchn, &x, &y, 0)) { + obj_extract_self(saddle); + place_object(saddle, x, y); + stackobj(saddle); + } + return TRUE; + } + } + if (Has_contents(objchn) && + keep_saddle_with_steedcorpse(steed_mid, objchn->cobj, saddle)) + return TRUE; + objchn = objchn->nobj; + } + return FALSE; +} +#endif /*STEED*/ + void dotrap(trap, trflags) register struct trap *trap; @@ -515,7 +587,8 @@ register struct obj *otmp; boolean already_seen = trap->tseen; boolean webmsgok = (!(trflags & NOWEBMSG)); - + boolean forcebungle = (trflags & FORCEBUNGLE); + nomul(0); /* KMH -- You can't escape the Sokoban level traps */ @@ -541,7 +614,8 @@ defsyms[trap_to_defsym(ttype)].explanation); return; } - if(!Fumbling && ttype != MAGIC_PORTAL && ttype != ANTI_MAGIC && + if(!Fumbling && ttype != MAGIC_PORTAL && + ttype != ANTI_MAGIC && !forcebungle && (!rn2(5) || ((ttype == PIT || ttype == SPIKED_PIT) && is_clinger(youmonst.data)))) { You("escape %s %s.", @@ -558,6 +632,13 @@ switch(ttype) { case ARROW_TRAP: + if (trap->once && trap->tseen && !rn2(15)) { + You_hear("a loud click!"); + deltrap(trap); + newsym(u.ux,u.uy); + break; + } + trap->once = 1; seetrap(trap); pline("An arrow shoots out at you!"); otmp = mksobj(ARROW, TRUE, FALSE); @@ -578,6 +659,13 @@ } break; case DART_TRAP: + if (trap->once && trap->tseen && !rn2(15)) { + You_hear("a soft click."); + deltrap(trap); + newsym(u.ux,u.uy); + break; + } + trap->once = 1; seetrap(trap); pline("A little dart shoots out at you!"); otmp = mksobj(DART, TRUE, FALSE); @@ -590,7 +678,7 @@ #endif if (thitu(7, dmgval(otmp, &youmonst), otmp, "little dart")) { if (otmp->opoisoned) - poisoned("dart",A_CON,"poison dart",10); + poisoned("dart", A_CON, "little dart", -10); obfree(otmp, (struct obj *)0); } else { place_object(otmp, u.ux, u.uy); @@ -600,17 +688,24 @@ } break; case ROCKTRAP: - { + if (trap->once && trap->tseen && !rn2(15)) { + pline("A trap door in %s opens, but nothing falls out!", + the(ceiling(u.ux,u.uy))); + deltrap(trap); + newsym(u.ux,u.uy); + } else { int dmg = d(2,6); /* should be std ROCK dmg? */ + trap->once = 1; seetrap(trap); otmp = mksobj_at(ROCK, u.ux, u.uy, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); - pline("A trap door in the %s opens and a rock falls on your %s!", - ceiling(u.ux,u.uy), - body_part(HEAD)); + pline("A trap door in %s opens and %s falls on your %s!", + the(ceiling(u.ux,u.uy)), + an(xname(otmp)), + body_part(HEAD)); if (uarmh) { if(is_metallic(uarmh)) { @@ -778,12 +873,18 @@ if (!In_sokoban(&u.uz)) { char verbbuf[BUFSZ]; #ifdef STEED - if (u.usteed) - Sprintf(verbbuf,"lead %s", + if (u.usteed) { + if ((trflags & RECURSIVETRAP) != 0) + Sprintf(verbbuf, "and %s fall", + x_monnam(u.usteed, + u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, + (char *)0, SUPPRESS_SADDLE, FALSE)); + else + 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]); @@ -1002,7 +1103,11 @@ } break; } - case LANDMINE: + case LANDMINE: { +#ifdef STEED + unsigned steed_mid = 0; + struct obj *saddle; +#endif if (Levitation || Flying) { if (!already_seen && rn2(3)) break; seetrap(trap); @@ -1011,7 +1116,9 @@ trap->madeby_u ? "the trigger of your mine" : "a trigger"); if (already_seen && rn2(3)) break; - pline("KAABLAMM!!! The air currents set %s%s off!", + pline("KAABLAMM!!! %s %s%s off!", + forcebungle ? "Your inept attempt sets" : + "The air currents set", already_seen ? a_your[trap->madeby_u] : "", already_seen ? " land mine" : "it"); } else { @@ -1028,22 +1135,28 @@ pline("KAABLAMM!!! You triggered %s land mine!", a_your[trap->madeby_u]); #ifdef STEED + if (u.usteed) steed_mid = u.usteed->m_id; recursive_mine = TRUE; (void) steedintrap(trap, (struct obj *)0); recursive_mine = FALSE; + saddle = sobj_at(SADDLE,u.ux, u.uy); #endif set_wounded_legs(LEFT_SIDE, rn1(35, 41)); set_wounded_legs(RIGHT_SIDE, rn1(35, 41)); exercise(A_DEX, FALSE); } blow_up_landmine(trap); +#ifdef STEED + if (steed_mid && saddle && !u.usteed) + (void)keep_saddle_with_steedcorpse(steed_mid, fobj, saddle); +#endif newsym(u.ux,u.uy); /* update trap symbol */ losehp(rnd(16), "land mine", KILLED_BY_AN); /* fall recursively into the pit... */ - if ((trap = t_at(u.ux, u.uy)) != 0) dotrap(trap, 0); + if ((trap = t_at(u.ux, u.uy)) != 0) dotrap(trap, RECURSIVETRAP); fill_pit(u.ux, u.uy); break; - + } case ROLLING_BOULDER_TRAP: { int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0); @@ -1176,6 +1289,7 @@ /* caller may subsequently fill pit, e.g. with a boulder */ trap->ttyp = PIT; /* explosion creates a pit */ trap->madeby_u = FALSE; /* resulting pit isn't yours */ + seetrap(trap); /* and it isn't concealed */ } #endif /* OVLB */ @@ -1241,11 +1355,20 @@ dx = sgn(x2 - x1); dy = sgn(y2 - y1); switch (style) { + case ROLL|LAUNCH_UNSEEN: + if (otyp == BOULDER) { + You_hear(Hallucination ? + "someone bowling." : + "rumbling in the distance."); + } + style &= ~LAUNCH_UNSEEN; + goto roll; case ROLL|LAUNCH_KNOWN: /* use otrapped as a flag to ohitmon */ singleobj->otrapped = 1; style &= ~LAUNCH_KNOWN; /* fall through */ + roll: case ROLL: delaycnt = 2; /* fall through */ @@ -1587,15 +1710,23 @@ unreasonable; everybody has their own style. */ if (trap->madeby_u && rnl(5)) setmangry(mtmp); - /* 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); + see_it = cansee(mtmp->mx, mtmp->my); #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: + if (trap->once && trap->tseen && !rn2(15)) { + if (in_sight && see_it) + pline("%s triggers a trap but nothing happens.", + Monnam(mtmp)); + deltrap(trap); + newsym(mtmp->mx, mtmp->my); + break; + } + trap->once = 1; otmp = mksobj(ARROW, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); @@ -1604,6 +1735,15 @@ if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; break; case DART_TRAP: + if (trap->once && trap->tseen && !rn2(15)) { + if (in_sight && see_it) + pline("%s triggers a trap but nothing happens.", + Monnam(mtmp)); + deltrap(trap); + newsym(mtmp->mx, mtmp->my); + break; + } + trap->once = 1; otmp = mksobj(DART, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); @@ -1612,6 +1752,15 @@ if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; break; case ROCKTRAP: + if (trap->once && trap->tseen && !rn2(15)) { + if (in_sight && see_it) + pline("A trap door above %s opens, but nothing falls out!", + mon_nam(mtmp)); + deltrap(trap); + newsym(mtmp->mx, mtmp->my); + break; + } + trap->once = 1; otmp = mksobj(ROCK, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); @@ -1734,7 +1883,6 @@ } case FIRE_TRAP: mfiretrap: - see_it = cansee(mtmp->mx, mtmp->my); if (in_sight) pline("A %s erupts from the %s under %s!", tower_of_flame, @@ -1977,24 +2125,23 @@ case ROLLING_BOULDER_TRAP: if (!is_flyer(mptr)) { + int style = ROLL | (in_sight ? 0 : LAUNCH_UNSEEN); + newsym(mtmp->mx,mtmp->my); if (in_sight) - pline("Click! %s triggers %s.", Monnam(mtmp), + pline("Click! %s triggers %s.", Monnam(mtmp), trap->tseen ? "a rolling boulder trap" : something); if (launch_obj(BOULDER, trap->launch.x, trap->launch.y, - trap->launch2.x, trap->launch2.y, ROLL)) { - if (in_sight) trap->tseen = TRUE; - else You_hear(Hallucination ? - "someone bowling." : - "rumbling in the distance."); - if (mtmp->mhp <= 0) trapkilled = TRUE; + trap->launch2.x, trap->launch2.y, style)) { + if (in_sight) trap->tseen = TRUE; + if (mtmp->mhp <= 0) trapkilled = TRUE; } else { - deltrap(trap); - newsym(mtmp->mx,mtmp->my); + deltrap(trap); + newsym(mtmp->mx,mtmp->my); } - } + } break; default: @@ -2737,6 +2884,7 @@ } #endif crawl_ok = FALSE; + x = y = 0; /* lint suppression */ /* 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 */ @@ -3084,8 +3232,7 @@ /* successfully used oil or grease to fix squeaky board */ if (obj->otyp == CAN_OF_GREASE) { - check_unpaid(obj); - obj->spe--; + consume_obj_charge(obj, TRUE); } else { useup(obj); /* oil */ makeknown(POT_OIL); @@ -3320,17 +3467,25 @@ if(!u.dx && !u.dy) { for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if(Is_box(otmp)) { - Sprintf(qbuf, "There is %s here. Check it for traps?", doname(otmp)); + Sprintf(qbuf, "There is %s here. Check it for traps?", + safe_qbuf("", sizeof("There is here. Check it for traps?"), + doname(otmp), an(simple_typename(otmp->otyp)), "a box")); switch (ynq(qbuf)) { case 'q': return(0); case 'n': continue; } - +#ifdef STEED + if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { + You("aren't skilled enough to reach from %s.", + mon_nam(u.usteed)); + return(0); + } +#endif if((otmp->otrapped && (force || (!confused && rn2(MAXULEV + 1 - u.ulevel) < 10))) || (!force && confused && !rn2(3))) { You("find a trap on %s!", the(xname(otmp))); - exercise(A_WIS, TRUE); + if (!confused) exercise(A_WIS, TRUE); switch (ynq("Disarm it?")) { case 'q': return(1); @@ -3580,7 +3735,7 @@ case 0: pline("A cloud of %s gas billows from %s.", Blind ? blindgas[rn2(SIZE(blindgas))] : - hcolor((char *)0), the(xname(obj))); + rndcolor(), the(xname(obj))); if(!Stunned) { if (Hallucination) pline("What a groovy feeling!"); diff -Naurd ../nethack-3.4.1/src/u_init.c ./src/u_init.c --- ../nethack-3.4.1/src/u_init.c Sun Feb 23 14:43:31 2003 +++ ./src/u_init.c Mon Sep 1 14:33:32 2003 @@ -583,7 +583,7 @@ aligns[flags.initalign].value; u.ulycn = NON_PM; -#ifdef BSD +#if defined(BSD) && !defined(POSIX_TYPES) (void) time((long *)&u.ubirthday); #else (void) time(&u.ubirthday); diff -Naurd ../nethack-3.4.1/src/uhitm.c ./src/uhitm.c --- ../nethack-3.4.1/src/uhitm.c Sun Feb 23 14:43:31 2003 +++ ./src/uhitm.c Mon Sep 1 14:33:32 2003 @@ -815,12 +815,16 @@ mon->mcansee ? "" : " further"); } else { char *whom = mon_nam(mon); + char *what = The(xname(obj)); + if (!thrown && obj->quan > 1) + what = An(singular(obj, xname)); /* note: s_suffix returns a modifiable buffer */ if (haseyes(mdat) && mdat != &mons[PM_FLOATING_EYE]) - whom = strcat(s_suffix(whom), " face"); - pline_The("%s splashes over %s!", - xname(obj), whom); + whom = strcat(strcat(s_suffix(whom), " "), + mbodypart(mon, FACE)); + pline("%s %s over %s!", + what, vtense(what, "splash"), whom); } setmangry(mon); mon->mcansee = 0; @@ -942,6 +946,7 @@ /* avoid migrating a dead monster */ if (mon->mhp > tmp) { mhurtle(mon, u.dx, u.dy, 1); + mdat = mon->data; /* in case of a polymorph trap */ if (DEADMONSTER(mon)) already_killed = TRUE; } hittxt = TRUE; @@ -958,6 +963,7 @@ /* avoid migrating a dead monster */ if (mon->mhp > tmp) { mhurtle(mon, u.dx, u.dy, 1); + mdat = mon->data; /* in case of a polymorph trap */ if (DEADMONSTER(mon)) already_killed = TRUE; } hittxt = TRUE; @@ -2197,6 +2203,9 @@ if (aatyp == AT_KICK) { obj = uarmf; if (!obj) break; + } else if (aatyp == AT_BITE || aatyp == AT_BUTT || + (aatyp >= AT_STNG && aatyp < AT_WEAP)) { + break; /* no object involved */ } passive_obj(mon, obj, &(ptr->mattk[i])); } diff -Naurd ../nethack-3.4.1/src/version.c ./src/version.c --- ../nethack-3.4.1/src/version.c Sun Feb 23 14:43:31 2003 +++ ./src/version.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)version.c 3.4 2003/02/19 */ +/* SCCS Id: @(#)version.c 3.4 2003/08/21 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ diff -Naurd ../nethack-3.4.1/src/vision.c ./src/vision.c --- ../nethack-3.4.1/src/vision.c Sun Feb 23 14:43:31 2003 +++ ./src/vision.c Mon Sep 1 14:33:32 2003 @@ -587,7 +587,7 @@ next_rmin[row] = min(next_rmin[row], col); next_rmax[row] = max(next_rmax[row], col); - next_array[row][col] = IN_SIGHT; + next_array[row][col] = IN_SIGHT | COULD_SEE; } } @@ -601,7 +601,7 @@ next_row = next_array[row]; for(col=next_rmin[row]; col <= next_rmax[row]; col++) - next_row[col] = IN_SIGHT; + next_row[col] = IN_SIGHT | COULD_SEE; } } else view_from(u.uy, u.ux, next_array, next_rmin, next_rmax, @@ -1519,7 +1519,9 @@ q3_path(row1,col1,row2,col2,cleardone); } } +#ifdef MACRO_CPATH cleardone: +#endif return((boolean)result); } @@ -1664,6 +1666,9 @@ char *row_max; /* right most */ int lim_max; /* right most limit of circle */ +#ifdef GCC_WARN + rowp = 0; +#endif nrow = row + step; deeper = good_row(nrow) && (!limits || (*limits >= *(limits+1))); if(!vis_func) { @@ -1916,6 +1921,9 @@ char *row_max; /* right most */ int lim_min; +#ifdef GCC_WARN + rowp = 0; +#endif nrow = row + step; deeper = good_row(nrow) && (!limits || (*limits >= *(limits+1))); if(!vis_func) { diff -Naurd ../nethack-3.4.1/src/were.c ./src/were.c --- ../nethack-3.4.1/src/were.c Sun Feb 23 14:43:31 2003 +++ ./src/were.c Mon Sep 1 14:33:32 2003 @@ -15,16 +15,16 @@ if (is_human(mon->data)) { if (!Protection_from_shape_changers && - !rn2(night() ? (flags.moonphase == FULL_MOON ? 3 : 30) - : (flags.moonphase == FULL_MOON ? 10 : 50))) { + !rn2(night() ? (flags.moonphase == FULL_MOON ? 3 : 30) + : (flags.moonphase == FULL_MOON ? 10 : 50))) { new_were(mon); /* change into animal form */ - if (flags.soundok) { + if (flags.soundok && !canseemon(mon)) { const char *howler; switch (monsndx(mon->data)) { - case PM_HUMAN_WEREWOLF: howler = "wolf"; break; - case PM_HUMAN_WEREJACKAL: howler = "jackal"; break; - default: howler = (char *)0; break; + case PM_WEREWOLF: howler = "wolf"; break; + case PM_WEREJACKAL: howler = "jackal"; break; + default: howler = (char *)0; break; } if (howler) You_hear("a %s howling at the moon.", howler); diff -Naurd ../nethack-3.4.1/src/zap.c ./src/zap.c --- ../nethack-3.4.1/src/zap.c Sun Feb 23 14:43:32 2003 +++ ./src/zap.c Mon Sep 1 14:33:32 2003 @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)zap.c 3.4 2003/02/08 */ +/* SCCS Id: @(#)zap.c 3.4 2003/08/24 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -507,10 +507,16 @@ mtmp2->mtrapped = 0; mtmp2->msleeping = 0; mtmp2->mfrozen = 0; - mtmp2->mcan = 0; + mtmp2->mcanmove = 1; + /* most cancelled monsters return to normal, + but some need to stay cancelled */ + if (!dmgtype(mtmp2->data, AD_SEDU) +#ifdef SEDUCE + && !dmgtype(mtmp2->data, AD_SSEX) +#endif + ) mtmp2->mcan = 0; mtmp2->mcansee = 1; /* set like in makemon */ mtmp2->mblinded = 0; - mtmp2->mcanmove = 1; /* set like in makemon */ mtmp2->mstun = 0; mtmp2->mconf = 0; replmon(mtmp,mtmp2); @@ -1674,6 +1680,8 @@ else Norep("You smell a delicious smell."); break; + case WEAPON_CLASS: /* crysknife */ + /* fall through */ default: res = 0; break; @@ -2556,7 +2564,8 @@ register struct monst *mtmp; register const char *force; /* usually either "." or "!" */ { - if((!cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) + if((!cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp) && + !(u.uswallow && mtmp == u.ustuck)) || !flags.verbose) pline("%s %s it.", The(str), vtense(str, "hit")); else pline("%s %s %s%s", The(str), vtense(str, "hit"), @@ -2779,6 +2788,32 @@ break; /* physical objects fall onto sink */ #endif } + /* limit range of ball so hero won't make an invalid move */ + if (weapon == THROWN_WEAPON && range > 0 && + obj->otyp == HEAVY_IRON_BALL) { + struct obj *bobj; + struct trap *t; + if ((bobj = sobj_at(BOULDER, x, y)) != 0) { + if (cansee(x,y)) + pline("%s hits %s.", + The(distant_name(obj, xname)), an(xname(bobj))); + range = 0; + } else if (obj == uball) { + if (!test_move(x - ddx, y - ddy, ddx, ddy, TEST_MOVE)) { + /* nb: it didn't hit anything directly */ + if (cansee(x,y)) + pline("%s jerks to an abrupt halt.", + The(distant_name(obj, xname))); /* lame */ + range = 0; + } else if (In_sokoban(&u.uz) && (t = t_at(x, y)) != 0 && + (t->ttyp == PIT || t->ttyp == SPIKED_PIT || + t->ttyp == HOLE || t->ttyp == TRAPDOOR)) { + /* hero falls into the trap, so ball stops */ + range = 0; + } + } + } + /* thrown/kicked missile has moved away from its starting spot */ point_blank = FALSE; /* affects passing through iron bars */ } @@ -3601,6 +3636,7 @@ if (u.uinwater) { /* not just `if (Underwater)' */ /* leave the no longer existent water */ u.uinwater = 0; + u.uundetected = 0; docrt(); vision_full_recalc = 1; } else if (u.utrap && u.utraptype == TT_LAVA) { @@ -3755,7 +3791,7 @@ obj_extract_self(item); place_object(item, obj->ox, obj->oy); } - if (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && obj->spe) { + if (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (obj->spe & STATUE_HISTORIC)) { You_feel("guilty about damaging such a historic statue."); adjalign(-1); } diff -Naurd ../nethack-3.4.1/sys/share/NetHack.cnf ./sys/share/NetHack.cnf --- ../nethack-3.4.1/sys/share/NetHack.cnf Sun Feb 23 14:43:37 2003 +++ ./sys/share/NetHack.cnf Mon Sep 1 14:33:32 2003 @@ -55,7 +55,10 @@ # General options. You might also set "silent" so as not to attract # the boss's attention. # -OPTIONS=time,noshowexp,number_pad,lit_corridor,rest_on_space +# number_pad option can have an optional value of 0 (off), 1 (on), +# or 2(on,legacy-mode) which causes 5='g', alt-5='G', alt-0='I' +# +OPTIONS=time,noshowexp,number_pad:2,lit_corridor,rest_on_space # # If you want to get rid of "use #quit to quit..." use: #OPTIONS=suppress_alert:3.3.1 diff -Naurd ../nethack-3.4.1/sys/share/lev_yacc.c ./sys/share/lev_yacc.c --- ../nethack-3.4.1/sys/share/lev_yacc.c Sun Feb 23 14:43:37 2003 +++ ./sys/share/lev_yacc.c Mon Sep 1 14:33:32 2003 @@ -1138,6 +1138,9 @@ yyerror("Invalid background type."); init_lev.smoothed = yyvsp[-6].i; init_lev.joined = yyvsp[-4].i; + if (init_lev.joined && + init_lev.fg != CORR && init_lev.fg != ROOM) + yyerror("Invalid foreground type for joined map."); init_lev.lit = yyvsp[-2].i; init_lev.walled = yyvsp[0].i; yyval.i = 1; diff -Naurd ../nethack-3.4.1/util/lev_comp.y ./util/lev_comp.y --- ../nethack-3.4.1/util/lev_comp.y Sun Feb 23 14:43:43 2003 +++ ./util/lev_comp.y Mon Sep 1 14:33:32 2003 @@ -274,6 +274,9 @@ yyerror("Invalid background type."); init_lev.smoothed = $7; init_lev.joined = $9; + if (init_lev.joined && + init_lev.fg != CORR && init_lev.fg != ROOM) + yyerror("Invalid foreground type for joined map."); init_lev.lit = $11; init_lev.walled = $13; $$ = 1; diff -Naurd ../nethack-3.4.1/util/makedefs.c ./util/makedefs.c --- ../nethack-3.4.1/util/makedefs.c Sun Feb 23 14:43:43 2003 +++ ./util/makedefs.c Mon Sep 1 14:33:32 2003 @@ -78,7 +78,8 @@ # define DATA_TEMPLATE "NH:slib/%s" # define DATA_IN_TEMPLATE "NH:dat/%s" #else /* not AMIGA */ -# ifdef MAC +# if defined(MAC) && !defined(__MACH__) + /* MacOS 9 or earlier */ # define INCLUDE_TEMPLATE ":include:%s" # define SOURCE_TEMPLATE ":src:%s" # define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */ @@ -645,7 +646,7 @@ "Keystone Kops", #endif #ifdef HOLD_LOCKFILE_OPEN - "exlusive lock on level 0 file", + "exclusive lock on level 0 file", #endif #ifdef LOGFILE "log file",