diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 02f3e4e8d..6b853e1f1 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -906,6 +906,7 @@ shopkeepers give honorifics to vampires and elves when commands (D, A, object identify) mix object class filtering with BUCX filtering, take the intersection rather than the union (so ?B picks blessed scrolls rather than all scrolls plus blessed everything) +bmask is stored with the objects on the Plane of Water to prevent segfault Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index a185be710..741de9138 100644 --- a/include/extern.h +++ b/include/extern.h @@ -515,6 +515,7 @@ E void FDECL(switch_symbols, (int)); E void FDECL(assign_graphics, (int)); E void NDECL(init_r_symbols); E void NDECL(init_symbols); +E void NDECL(update_bouldersym); E void NDECL(init_showsyms); E void NDECL(init_l_symbols); E void FDECL(clear_symsetentry, (int,BOOLEAN_P)); diff --git a/include/lev.h b/include/lev.h index e3e05ec9a..b2a99841a 100644 --- a/include/lev.h +++ b/include/lev.h @@ -13,6 +13,8 @@ #define WRITE_SAVE 0x2 #define FREE_SAVE 0x4 +#define MAX_BMASK 4 + /* operations of the various saveXXXchn & co. routines */ #define perform_bwrite(mode) ((mode) & (COUNT_SAVE|WRITE_SAVE)) #define release_data(mode) ((mode) & FREE_SAVE) @@ -33,7 +35,7 @@ struct container { struct bubble { xchar x, y; /* coordinates of the upper left corner */ schar dx, dy; /* the general direction of the bubble's movement */ - uchar *bm; /* pointer to the bubble bit mask */ + uchar bm[MAX_BMASK+2]; /* bubble bit mask */ struct bubble *prev, *next; /* need to traverse the list up and down */ struct container *cons; }; diff --git a/src/drawing.c b/src/drawing.c index d78668e0a..7967831d3 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -350,6 +350,14 @@ init_symbols() init_r_symbols(); } +void +update_bouldersym() +{ + showsyms[SYM_BOULDER + SYM_OFF_X] = iflags.bouldersym; + l_syms[SYM_BOULDER + SYM_OFF_X] = iflags.bouldersym; + r_syms[SYM_BOULDER + SYM_OFF_X] = iflags.bouldersym; +} + void init_showsyms() { diff --git a/src/invent.c b/src/invent.c index 176d2b8d2..1a2a3b2dd 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1906,6 +1906,7 @@ long* out_cnt; } start_menu(win); + any = zeroany; if (wizard && iflags.override_ID) { char prompt[BUFSZ]; any.a_char = -1; diff --git a/src/mkmaze.c b/src/mkmaze.c index 923a51f1d..22e60df4f 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1262,6 +1262,9 @@ register int x, y, n; impossible("n too large (mk_bubble)"); n = SIZE(bmask) - 1; } + if (bmask[n][1] > MAX_BMASK) { + panic("bmask size is larger than MAX_BMASK"); + } b = (struct bubble *)alloc(sizeof(struct bubble)); if ((x + (int) bmask[n][0] - 1) > bxmax) x = bxmax - bmask[n][0] + 1; if ((y + (int) bmask[n][1] - 1) > bymax) y = bymax - bmask[n][1] + 1; @@ -1269,7 +1272,9 @@ register int x, y, n; b->y = y; b->dx = 1 - rn2(3); b->dy = 1 - rn2(3); - b->bm = bmask[n]; + /* y dimension is the length of bitmap data - see bmask above */ + (void)memcpy((genericptr_t)b->bm, (genericptr_t)bmask[n], + (bmask[n][1]+2)*sizeof(b->bm[0])); b->cons = 0; if (!bbubbles) bbubbles = b; if (ebubbles) { diff --git a/src/mkobj.c b/src/mkobj.c index 699c5dbdb..50f2b5b7e 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 mkobj.c $NHDT-Date: 1428715841 2015/04/11 01:30:41 $ $NHDT-Branch: master $:$NHDT-Revision: 1.91 $ */ +/* NetHack 3.5 mkobj.c $NHDT-Date: 1430472720 2015/05/01 09:32:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.95 $ */ /* NetHack 3.5 mkobj.c $Date: 2012/03/10 02:49:08 $ $Revision: 1.70 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -16,6 +16,7 @@ STATIC_DCL const char *FDECL(where_name, (struct obj *)); STATIC_DCL void FDECL(insane_object, (struct obj *,const char *,const char *,struct monst *)); STATIC_DCL void FDECL(check_contained, (struct obj *,const char *)); +STATIC_DCL void FDECL(sanity_check_worn, (struct obj *)); struct icp { int iprob; /* probability of an item type */ @@ -1968,18 +1969,18 @@ obj_sanity_check() those objects should have already been sanity checked via the floor list so container contents are skipped here */ for (x = 0; x < COLNO; x++) - for (y = 0; y < ROWNO; y++) + for (y = 0; y < ROWNO; y++) for (obj = level.objects[x][y]; obj; obj = obj->nexthere) { - /* should match ; <0,*> should always be empty */ - if (obj->where != OBJ_FLOOR || x == 0 || - obj->ox != x || obj->oy != y) { - char at_fmt[BUFSZ]; + /* should match ; <0,*> should always be empty */ + if (obj->where != OBJ_FLOOR || x == 0 || + obj->ox != x || obj->oy != y) { + char at_fmt[BUFSZ]; - Sprintf(at_fmt, "%%s obj@<%d,%d> %%s %%s: %%s@<%d,%d>", - x, y, obj->ox, obj->oy); - insane_object(obj, at_fmt, "location sanity", - (struct monst *)0); - } + Sprintf(at_fmt, "%%s obj@<%d,%d> %%s %%s: %%s@<%d,%d>", + x, y, obj->ox, obj->oy); + insane_object(obj, at_fmt, "location sanity", + (struct monst *)0); + } } objlist_sanity(invent, OBJ_INVENT, "invent sanity"); @@ -1992,16 +1993,16 @@ obj_sanity_check() /* monsters temporarily in transit; they should have arrived with hero by the time we get called */ if (mydogs) { - pline("mydogs sanity [not empty]"); - mon_obj_sanity(mydogs, "mydogs minvent sanity"); + pline("mydogs sanity [not empty]"); + mon_obj_sanity(mydogs, "mydogs minvent sanity"); } /* objects temporarily freed from invent/floor lists; they should have arrived somewhere by the time we get called */ if (thrownobj) - insane_object(thrownobj, ofmt3, "thrownobj sanity", (struct monst *)0); + insane_object(thrownobj, ofmt3, "thrownobj sanity", (struct monst *)0); if (kickedobj) - insane_object(kickedobj, ofmt3, "kickedobj sanity", (struct monst *)0); + insane_object(kickedobj, ofmt3, "kickedobj sanity", (struct monst *)0); /* [how about current_wand too?] */ } @@ -2015,15 +2016,40 @@ const char *mesg; struct obj *obj; for (obj = objlist; obj; obj = obj->nobj) { - if (obj->where != wheretype) - insane_object(obj, ofmt0, mesg, (struct monst *)0); - if (Has_contents(obj)) { - if (wheretype == OBJ_ONBILL) - /* containers on shop bill should always be empty */ - insane_object(obj, "%s obj contains something! %s %s: %s", - mesg, (struct monst *)0); - check_contained(obj, mesg); - } + if (obj->where != wheretype) + insane_object(obj, ofmt0, mesg, (struct monst *)0); + if (Has_contents(obj)) { + if (wheretype == OBJ_ONBILL) + /* containers on shop bill should always be empty */ + insane_object(obj, "%s obj contains something! %s %s: %s", + mesg, (struct monst *)0); + check_contained(obj, mesg); + } + if (obj->owornmask) { + char maskbuf[40]; + boolean bc_ok = FALSE; + + switch (obj->where) { + case OBJ_INVENT: + case OBJ_MINVENT: + case OBJ_MIGRATING: + sanity_check_worn(obj); + break; + case OBJ_FLOOR: + /* note: ball and chain can also be OBJ_FREE, but not across + turns so this sanity check shouldn't encounter that */ + bc_ok = TRUE; + /*FALLTHRU*/ + default: + if ((obj != uchain && obj != uball) || !bc_ok) { + /* discovered an object not in inventory which + erroneously has worn mask set */ + Sprintf(maskbuf, "worn mask 0x%08lx", obj->owornmask); + insane_object(obj, ofmt0, maskbuf, (struct monst *)0); + } + break; + } + } } } @@ -2037,18 +2063,18 @@ const char *mesg; struct obj *obj; for (mon = monlist; mon; mon = mon->nmon) - for (obj = mon->minvent; obj; obj = obj->nobj) { - if (obj->where != OBJ_MINVENT) - insane_object(obj, mfmt1, mesg, mon); - if (obj->ocarry != mon) - insane_object(obj, mfmt2, mesg, mon); - check_contained(obj, mesg); - } + for (obj = mon->minvent; obj; obj = obj->nobj) { + if (obj->where != OBJ_MINVENT) + insane_object(obj, mfmt1, mesg, mon); + if (obj->ocarry != mon) + insane_object(obj, mfmt2, mesg, mon); + check_contained(obj, mesg); + } } /* This must stay consistent with the defines in obj.h. */ static const char *obj_state_names[NOBJ_STATES] = { - "free", "floor", "contained", "invent", + "free", "floor", "contained", "invent", "minvent", "migrating", "buried", "onbill" }; @@ -2062,8 +2088,8 @@ struct obj *obj; if (!obj) return "nowhere"; where = obj->where; if (where < 0 || where >= NOBJ_STATES || !obj_state_names[where]) { - Sprintf(unknown, "unknown[%d]", where); - return unknown; + Sprintf(unknown, "unknown[%d]", where); + return unknown; } return obj_state_names[where]; } @@ -2079,19 +2105,19 @@ struct monst *mon; objnm = monnm = "null!"; if (obj) { - iflags.override_ID++; - objnm = doname(obj); - iflags.override_ID--; + iflags.override_ID++; + objnm = doname(obj); + iflags.override_ID--; } if (mon || (strstri(mesg, "minvent") && !strstri(mesg, "contained"))) { - Strcat(strcpy(altfmt, fmt), " held by mon %s (%s)"); - if (mon) - monnm = x_monnam(mon, ARTICLE_A, (char *)0, EXACT_NAME, TRUE); - pline(altfmt, mesg, - fmt_ptr((genericptr_t)obj), where_name(obj), objnm, - fmt_ptr((genericptr_t)mon), monnm); + Strcat(strcpy(altfmt, fmt), " held by mon %s (%s)"); + if (mon) + monnm = x_monnam(mon, ARTICLE_A, (char *)0, EXACT_NAME, TRUE); + pline(altfmt, mesg, + fmt_ptr((genericptr_t)obj), where_name(obj), objnm, + fmt_ptr((genericptr_t)mon), monnm); } else { - pline(fmt, mesg, fmt_ptr((genericptr_t)obj), where_name(obj), objnm); + pline(fmt, mesg, fmt_ptr((genericptr_t)obj), where_name(obj), objnm); } } @@ -2109,37 +2135,122 @@ check_contained(container, mesg) /* change "invent sanity" to "contained invent sanity" but leave "nested contained invent sanity" as is */ if (!strstri(mesg, "contained")) - mesg = strcat(strcpy(mesgbuf, "contained "), mesg); + mesg = strcat(strcpy(mesgbuf, "contained "), mesg); for (obj = container->cobj; obj; obj = obj->nobj) { - /* catch direct cycle to avoid unbounded recursion */ - if (obj == container) - panic("failed sanity check: container holds itself"); - if (obj->where != OBJ_CONTAINED) - insane_object(obj, "%s obj %s %s: %s", mesg, (struct monst *)0); - else if (obj->ocontainer != container) - pline("%s obj %s in container %s, not %s", mesg, - fmt_ptr((genericptr_t)obj), - fmt_ptr((genericptr_t)obj->ocontainer), - fmt_ptr((genericptr_t)container)); + /* catch direct cycle to avoid unbounded recursion */ + if (obj == container) + panic("failed sanity check: container holds itself"); + if (obj->where != OBJ_CONTAINED) + insane_object(obj, "%s obj %s %s: %s", mesg, (struct monst *)0); + else if (obj->ocontainer != container) + pline("%s obj %s in container %s, not %s", mesg, + fmt_ptr((genericptr_t)obj), + fmt_ptr((genericptr_t)obj->ocontainer), + fmt_ptr((genericptr_t)container)); - if (Has_contents(obj)) { - /* catch most likely indirect cycle; we won't notice if - parent is present when something comes before it, or - notice more deeply embedded cycles (grandparent, &c) */ - if (obj->cobj == container) - panic("failed sanity check: container holds its parent"); - /* change "contained... sanity" to "nested contained... sanity" - and "nested contained..." to "nested nested contained..." */ - Strcpy(nestedmesg, "nested "); - copynchars(eos(nestedmesg), mesg, - (int)sizeof nestedmesg - (int)strlen(nestedmesg) - 1); - /* recursively check contents */ - check_contained(obj, nestedmesg); - } + if (Has_contents(obj)) { + /* catch most likely indirect cycle; we won't notice if + parent is present when something comes before it, or + notice more deeply embedded cycles (grandparent, &c) */ + if (obj->cobj == container) + panic("failed sanity check: container holds its parent"); + /* change "contained... sanity" to "nested contained... sanity" + and "nested contained..." to "nested nested contained..." */ + Strcpy(nestedmesg, "nested "); + copynchars(eos(nestedmesg), mesg, + (int)sizeof nestedmesg - (int)strlen(nestedmesg) - 1); + /* recursively check contents */ + check_contained(obj, nestedmesg); + } } } +/* check an object in hero's or monster's inventory which has worn mask set */ +STATIC_OVL void +sanity_check_worn(obj) +struct obj *obj; +{ +#if defined(BETA) || defined(DEBUG) + static unsigned long wearbits[] = { + W_ARM, W_ARMC, W_ARMH, W_ARMS, W_ARMG, W_ARMF, W_ARMU, + W_WEP, W_QUIVER, W_SWAPWEP, W_AMUL, W_RINGL, W_RINGR, + W_TOOL, W_SADDLE, W_BALL, W_CHAIN, + 0 + /* [W_ART,W_ARTI are property bits for items which aren't worn] */ + }; + char maskbuf[60]; + unsigned long allmask = 0L; + int i, n = 0; + + for (i = 0; wearbits[i]; ++i) { + allmask |= wearbits[i]; + if ((obj->owornmask & wearbits[i]) != 0L) ++n; + } + if (n > 1) { + /* multiple bits set */ + Sprintf(maskbuf, "worn mask (multiple) 0x%08lx", obj->owornmask); + insane_object(obj, ofmt0, maskbuf, (struct monst *)0); + } + if ((obj->owornmask & ~allmask) != 0L + || (carried(obj) && (obj->owornmask & W_SADDLE) != 0L)) { + /* non-wearable bit(s) set */ + Sprintf(maskbuf, "worn mask (bogus)) 0x%08lx", obj->owornmask); + insane_object(obj, ofmt0, maskbuf, (struct monst *)0); + } + if (n == 1 && (carried(obj) + || (obj->owornmask & (W_BALL|W_CHAIN)) != 0L)) { + const char *what = 0; + + /* verify that obj in hero's invent (or ball/chain elsewhere) + with owornmask of W_foo is the object pointed to by ufoo */ + switch (obj->owornmask) { + case W_ARM: if (obj != uarm) what = "armor"; /* suit */ + break; + case W_ARMC: if (obj != uarmc) what = "cloak"; + break; + case W_ARMH: if (obj != uarmh) what = "helm"; + break; + case W_ARMS: if (obj != uarms) what = "shield"; + break; + case W_ARMG: if (obj != uarmg) what = "gloves"; + break; + case W_ARMF: if (obj != uarmf) what = "boots"; + break; + case W_ARMU: if (obj != uarmu) what = "shirt"; + break; + case W_WEP: if (obj != uwep) what = "primary weapon"; + break; + case W_QUIVER: if (obj != uquiver) what = "quiver"; + break; + case W_SWAPWEP: if (obj != uswapwep) + what = u.twoweap ? "secondary weapon" : "alternate weapon"; + break; + case W_AMUL: if (obj != uamul) what = "amulet"; + break; + case W_RINGL: if (obj != uleft) what = "left ring"; + break; + case W_RINGR: if (obj != uright) what = "right ring"; + break; + case W_TOOL: if (obj != ublindf) what = "blindfold"; + break; + /* case W_SADDLE: */ + case W_BALL: if (obj != uball) what = "ball"; + break; + case W_CHAIN: if (obj != uchain) what = "chain"; + break; + default: break; + } + if (what) { + Sprintf(maskbuf, "worn mask 0x%08lx != %s", obj->owornmask, what); + insane_object(obj, ofmt0, maskbuf, (struct monst *)0); + } + } +#else /* not (BETA || DEBUG) */ + /* dummy use of obj to avoid "arg not used" complaint */ + if (!obj) insane_object(obj, ofmt0, "", (struct monst *)0); +#endif +} /* * wrapper to make "near this object" convenient diff --git a/src/mon.c b/src/mon.c index 7acc26670..a32032852 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 mon.c $NHDT-Date: 1430396792 2015/04/30 12:26:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.169 $ */ +/* NetHack 3.5 mon.c $NHDT-Date: 1430480373 2015/05/01 11:39:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.170 $ */ /* NetHack 3.5 mon.c $Date: 2012/05/16 02:15:10 $ $Revision: 1.126 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1850,7 +1850,7 @@ register struct monst *mtmp; u.uy = mtmp->my; u.uswallow = 0; u.uswldtim = 0; - if (Punished && uball->where == OBJ_FREE) placebc(); + if (Punished && uchain->where != OBJ_FLOOR) placebc(); vision_full_recalc = 1; docrt(); } diff --git a/src/options.c b/src/options.c index 8a5e65254..ec14cf766 100644 --- a/src/options.c +++ b/src/options.c @@ -744,6 +744,8 @@ initoptions_finish() /* result in the player's preferred fruit [better than "\033"]. */ obj_descr[SLIME_MOLD].oc_name = "fruit"; + if (iflags.bouldersym) update_bouldersym(); + reglyph_darkroom(); return; @@ -3571,6 +3573,7 @@ boolean setinitial,setfromfile; menu_item *sortl_pick = (menu_item *)0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); + any = zeroany; for (i = 0; i < SIZE(sortltype); i++) { sortl_name = sortltype[i]; any.a_char = *sortl_name; diff --git a/src/steal.c b/src/steal.c index f803ae4da..e3f09f524 100644 --- a/src/steal.c +++ b/src/steal.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 steal.c $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ +/* NetHack 3.5 steal.c $NHDT-Date: 1430528463 2015/05/02 01:01:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.53 $ */ /* NetHack 3.5 steal.c $Date: 2012/02/05 04:26:48 $ $Revision: 1.41 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -23,15 +23,31 @@ register struct obj *otmp; } long /* actually returns something that fits in an int */ -somegold(umoney) -long umoney; +somegold(lmoney) +long lmoney; { #ifdef LINT /* long conv. ok */ - return(0L); + int igold = 0; #else - return (long)( (umoney < 100) ? umoney : - (umoney > 10000) ? rnd(10000) : rnd((int) umoney) ); + int igold = (lmoney >= (long)LARGEST_INT) ? LARGEST_INT : (int)lmoney; #endif + + if (igold < 50) + ; /* all gold */ + else if (igold < 100) + igold = rn1(igold - 25 + 1, 25); + else if (igold < 500) + igold = rn1(igold - 50 + 1, 50); + else if (igold < 1000) + igold = rn1(igold - 100 + 1, 100); + else if (igold < 5000) + igold = rn1(igold - 500 + 1, 500); + else if (igold < 10000) + igold = rn1(igold - 1000 + 1, 1000); + else + igold = rn1(igold - 5000 + 1, 5000); + + return (long)igold; } /*