diff --git a/include/context.h b/include/context.h index b73499f97..0e7595ff9 100644 --- a/include/context.h +++ b/include/context.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 context.h $NHDT-Date: 1434421363 2015/06/16 02:22:43 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */ +/* NetHack 3.6 context.h $NHDT-Date: 1445215010 2015/10/19 00:36:50 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -76,6 +76,11 @@ struct polearm_info { unsigned m_id; /* monster id of hitmon, in save file */ }; +struct obj_split { + unsigned parent_oid, /* set: splitobj(), */ + child_oid; /* reset: clear_splitobjs() */ +}; + struct tribute_info { size_t tributesz; /* make it possible to skip this in future */ boolean enabled; /* Do we have tributes turned on? */ @@ -117,6 +122,7 @@ struct context_info { struct takeoff_info takeoff; struct warntype_info warntype; struct polearm_info polearm; + struct obj_split objsplit; /* track most recently split object stack */ struct tribute_info tribute; }; diff --git a/include/extern.h b/include/extern.h index 3bbcd4d54..bd22f7826 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1445126411 2015/10/18 00:00:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.508 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1445215014 2015/10/19 00:36:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.509 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1214,6 +1214,8 @@ E struct obj *FDECL(mkobj, (CHAR_P, BOOLEAN_P)); E int NDECL(rndmonnum); E boolean FDECL(bogon_is_pname, (CHAR_P)); E struct obj *FDECL(splitobj, (struct obj *, long)); +E struct obj *FDECL(unsplitobj, (struct obj *)); +E void NDECL(clear_splitobjs); E void FDECL(replace_object, (struct obj *, struct obj *)); E void FDECL(bill_dummy_object, (struct obj *)); E void FDECL(costly_alteration, (struct obj *, int)); diff --git a/include/patchlevel.h b/include/patchlevel.h index 4db87dae2..ca276c52c 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 patchlevel.h $NHDT-Date: 1432512782 2015/05/25 00:13:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.107 $ */ +/* NetHack 3.6 patchlevel.h $NHDT-Date: 1445215015 2015/10/19 00:36:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.109 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -8,7 +8,7 @@ /* * PATCHLEVEL is updated for each release. */ -#define PATCHLEVEL 0 +#define PATCHLEVEL 1 /* * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. diff --git a/src/allmain.c b/src/allmain.c index a60f2c4ac..aa68aa6a4 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 allmain.c $NHDT-Date: 1438505671 2015/08/02 08:54:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.62 $ */ +/* NetHack 3.6 allmain.c $NHDT-Date: 1445215016 2015/10/19 00:36:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.65 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -376,6 +376,7 @@ boolean resuming; /* once-per-player-input things go here */ /****************************************/ + clear_splitobjs(); find_ac(); if (!context.mv || Blind) { /* redo monsters if hallu or wearing a helm of telepathy */ diff --git a/src/dothrow.c b/src/dothrow.c index 9f065c5be..3ff1a5e07 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dothrow.c $NHDT-Date: 1444772016 2015/10/13 21:33:36 $ $NHDT-Branch: master $:$NHDT-Revision: 1.106 $ */ +/* NetHack 3.6 dothrow.c $NHDT-Date: 1445215018 2015/10/19 00:36:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.110 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -50,24 +50,10 @@ int shotlimit; * merge obj into another stack--usually quiver--even if it hadn't * been split from there (possibly triggering a panic in addinv), * and freeinv+addinv potentially has other side-effects. - * - * If obj came from splitobj(), it has been split from the item - * which precedes it in inventory and shares same inv letter. - * (This could get a false match if obj wasn't split from the - * preceding item and they're both using the overflow letter '#', - * but merging to have fewer '#' items should be a good thing, - * and we're not using addinv() so can't trigger its panic.) */ - for (otmp = invent; otmp; otmp = otmp->nobj) - if (otmp == obj) { - /* obj wasn't the result of splitobj, so we're done */ - break; - } else if (otmp->nobj == obj) { - if (otmp->invlet == obj->invlet) - (void) merged(&otmp, &obj); - /* found obj's preceding item, so no need to look further */ - break; - } + if (obj->o_id == context.objsplit.parent_oid + || obj->o_id == context.objsplit.child_oid) + (void) unsplitobj(obj); return 0; /* no time passes */ } @@ -108,11 +94,12 @@ int shotlimit; Sprintf(killer.name, "throwing %s bare-handed", killer_xname(obj)); instapetrify(killer.name); } - if (obj->otyp == TOWEL && obj->spe > 0) obj->spe--; if (welded(obj)) { weldmsg(obj); return 1; } + if (is_wet_towel(obj)) + dry_a_towel(obj, -1, FALSE); /* Multishot calculations * (potential volley of up to N missiles; default for N is 1) @@ -310,12 +297,13 @@ autoquiver() for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->owornmask || otmp->oartifact || !otmp->dknown) { ; /* Skip it */ - } else if (otmp->otyp == ROCK || + } else if (otmp->otyp == ROCK /* seen rocks or known flint or known glass */ - (objects[otmp->otyp].oc_name_known && otmp->otyp == FLINT) - || (objects[otmp->otyp].oc_name_known - && otmp->oclass == GEM_CLASS - && objects[otmp->otyp].oc_material == GLASS)) { + || (otmp->otyp == FLINT + && objects[otmp->otyp].oc_name_known) + || (otmp->oclass == GEM_CLASS + && objects[otmp->otyp].oc_material == GLASS + && objects[otmp->otyp].oc_name_known)) { if (uslinging()) oammo = otmp; else if (ammo_and_launcher(otmp, uswapwep)) @@ -327,8 +315,7 @@ autoquiver() player has to select them explicitly */ } else if (is_ammo(otmp)) { if (ammo_and_launcher(otmp, uwep)) - /* Ammo matched with launcher (bow and arrow, crossbow and - * bolt) */ + /* Ammo matched with launcher (bow+arrow, crossbow+bolt) */ oammo = otmp; else if (ammo_and_launcher(otmp, uswapwep)) altammo = otmp; diff --git a/src/invent.c b/src/invent.c index 02e747e29..b71b7c8c9 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1438652306 2015/08/04 01:38:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.170 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1445215019 2015/10/19 00:36:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.174 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -345,16 +345,16 @@ struct obj **potmp, **pobj; } /* -Adjust hero intrinsics as if this object was being added to the hero's -inventory. Called _before_ the object has been added to the hero's -inventory. - -This is called when adding objects to the hero's inventory normally (via -addinv) or when an object in the hero's inventory has been polymorphed -in-place. - -It may be valid to merge this code with with addinv_core2(). -*/ + * Adjust hero intrinsics as if this object was being added to the hero's + * inventory. Called _before_ the object has been added to the hero's + * inventory. + * + * This is called when adding objects to the hero's inventory normally (via + * addinv) or when an object in the hero's inventory has been polymorphed + * in-place. + * + * It may be valid to merge this code with with addinv_core2(). + */ void addinv_core1(obj) struct obj *obj; @@ -402,14 +402,14 @@ struct obj *obj; } /* -Adjust hero intrinsics as if this object was being added to the hero's -inventory. Called _after_ the object has been added to the hero's -inventory. - -This is called when adding objects to the hero's inventory normally (via -addinv) or when an object in the hero's inventory has been polymorphed -in-place. -*/ + * Adjust hero intrinsics as if this object was being added to the hero's + * inventory. Called _after_ the object has been added to the hero's + * inventory. + * + * This is called when adding objects to the hero's inventory normally (via + * addinv) or when an object in the hero's inventory has been polymorphed + * in-place. + */ void addinv_core2(obj) struct obj *obj; @@ -422,9 +422,9 @@ struct obj *obj; } /* -Add obj to the hero's inventory. Make sure the object is "free". -Adjust hero attributes as necessary. -*/ + * Add obj to the hero's inventory. Make sure the object is "free". + * Adjust hero attributes as necessary. + */ struct obj * addinv(obj) struct obj *obj; @@ -621,12 +621,12 @@ boolean maybe_unpaid; /* false if caller handles shop billing */ } /* -Adjust hero's attributes as if this object was being removed from the -hero's inventory. This should only be called from freeinv() and -where we are polymorphing an object already in the hero's inventory. - -Should think of a better name... -*/ + * Adjust hero's attributes as if this object was being removed from the + * hero's inventory. This should only be called from freeinv() and + * where we are polymorphing an object already in the hero's inventory. + * + * Should think of a better name... + */ void freeinv_core(obj) struct obj *obj; @@ -783,25 +783,26 @@ static const char *const currencies[] = { "Hong Kong Luna Dollar", /* The Moon is a Harsh Mistress */ "kongbuck", /* Snow Crash */ "nanite", /* System Shock 2 */ - "quatloo", /* Sim City */ + "quatloo", /* Star Trek, Sim City */ "simoleon", /* Sim City */ "solari", /* Spaceballs */ "spacebuck", /* Spaceballs */ "sporebuck", /* Spore */ "Triganic Pu", /* The Hitchhiker's Guide to the Galaxy */ "woolong", /* Cowboy Bebop */ + "zorkmid", /* Zork, NetHack */ }; const char * currency(amount) long amount; { - if (amount == 1L) - return (Hallucination ? currencies[rn2(SIZE(currencies))] - : "zorkmid"); - else - return (Hallucination ? makeplural(currencies[rn2(SIZE(currencies))]) - : "zorkmids"); + const char *res; + + res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid"; + if (amount != 1L) + res = makeplural(res); + return res; } boolean @@ -870,10 +871,10 @@ register int x, y; return ((struct obj *) 0); } +/* compact a string of inventory letters by dashing runs of letters */ STATIC_OVL void compactify(buf) register char *buf; -/* compact a string of inventory letters by dashing runs of letters */ { register int i1 = 1, i2 = 1; register char ilet, ilet1, ilet2; @@ -1619,18 +1620,18 @@ nextclass: ilet = 'a' - 1; if (*objchn && (*objchn)->oclass == COIN_CLASS) ilet--; /* extra iteration */ - /* - * Multiple Drop can change the invent chain while it operates - * (dropping a burning potion of oil while levitating creates - * an explosion which can destroy inventory items), so simple - * list traversal - * for (otmp = *objchn; otmp; otmp = otmp2) { - * otmp2 = otmp->nobj; - * ... - * } - * is inadequate here. Use each object's bypass bit to keep - * track of which list elements have already been processed. - */ + /* + * Multiple Drop can change the invent chain while it operates + * (dropping a burning potion of oil while levitating creates + * an explosion which can destroy inventory items), so simple + * list traversal + * for (otmp = *objchn; otmp; otmp = otmp2) { + * otmp2 = otmp->nobj; + * ... + * } + * is inadequate here. Use each object's bypass bit to keep + * track of which list elements have already been processed. + */ bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */ while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) { if (ilet == 'z') @@ -3257,7 +3258,8 @@ reassign() * user-assigned names, the 'count' portion being moved is * effectively renamed so that it will merge with 'to' stack. */ -int doorganize() /* inventory organizer by Del Lamb */ +int +doorganize() /* inventory organizer by Del Lamb */ { struct obj *obj, *otmp, *splitting, *bumped; int ix, cur, trycnt; @@ -3435,6 +3437,8 @@ int doorganize() /* inventory organizer by Del Lamb */ prinv(adj_type, obj, 0L); if (bumped) prinv("Moving:", bumped, 0L); + if (splitting) + clear_splitobjs(); /* reset splitobj context */ update_inventory(); return (0); } diff --git a/src/mkobj.c b/src/mkobj.c index 7c9e0be5d..f211c255c 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mkobj.c $NHDT-Date: 1444617220 2015/10/12 02:33:40 $ $NHDT-Branch: master $:$NHDT-Revision: 1.110 $ */ +/* NetHack 3.6 mkobj.c $NHDT-Date: 1445215021 2015/10/19 00:37:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.111 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -413,6 +413,9 @@ long num; obj->owt = weight(obj); otmp->quan = num; otmp->owt = weight(otmp); /* -= obj->owt ? */ + + context.objsplit.parent_oid = obj->o_id; + context.objsplit.child_oid = otmp->o_id; obj->nobj = otmp; /* Only set nexthere when on the floor, nexthere is also used */ /* as a back pointer to the container object when contained. */ @@ -430,6 +433,85 @@ long num; return otmp; } +/* try to find the stack obj was split from, then merge them back together; + returns the combined object if unsplit is successful, null otherwise */ +struct obj * +unsplitobj(obj) +struct obj *obj; +{ + unsigned target_oid = 0; + struct obj *oparent = 0, *ochild = 0, *list = 0; + + /* + * We don't operate on floor objects (we're following o->nobj rather + * than o->nexthere), on free objects (don't know which list to use when + * looking for obj's parent or child), on bill objects (too complicated, + * not needed), or on buried or migrating objects (not needed). + * [This could be improved, but at present additional generality isn't + * necessary.] + */ + switch (obj->where) { + case OBJ_FREE: + case OBJ_FLOOR: + case OBJ_ONBILL: + case OBJ_MIGRATING: + case OBJ_BURIED: + default: + return (struct obj *) 0; + case OBJ_INVENT: + list = invent; + break; + case OBJ_MINVENT: + list = obj->ocarry->minvent; + break; + case OBJ_CONTAINED: + list = obj->ocontainer->cobj; + break; + } + + /* first try the expected case; obj is split from another stack */ + if (obj->o_id == context.objsplit.child_oid) { + /* parent probably precedes child and will require list traversal */ + ochild = obj; + target_oid = context.objsplit.parent_oid; + if (obj->nobj && obj->nobj->o_id == target_oid) + oparent = obj->nobj; + } else if (obj->o_id == context.objsplit.parent_oid) { + /* alternate scenario: another stack was split from obj; + child probably follows parent and will be found here */ + oparent = obj; + target_oid = context.objsplit.child_oid; + if (obj->nobj && obj->nobj->o_id == target_oid) + ochild = obj->nobj; + } + /* if we have only half the split, scan obj's list to find other half */ + if (ochild && !oparent) { + /* expected case */ + for (obj = list; obj; obj = obj->nobj) + if (obj->o_id == target_oid) { + oparent = obj; + break; + } + } else if (oparent && !ochild) { + /* alternate scenario */ + for (obj = list; obj; obj = obj->nobj) + if (obj->o_id == target_oid) { + ochild = obj; + break; + } + } + /* if we have both parent and child, try to merge them; + if successful, return the combined stack, otherwise return null */ + return (oparent && ochild && merged(&oparent, &ochild)) ? oparent : 0; +} + +/* reset splitobj()/unsplitobj() context */ +void +clear_splitobjs() +{ + context.objsplit.parent_oid = context.objsplit.child_oid = 0; +} + /* * Insert otmp right after obj in whatever chain(s) it is on. Then extract * obj from the chain(s). This function does a literal swap. It is up to diff --git a/src/mon.c b/src/mon.c index a620fb592..1ed1695a3 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mon.c $NHDT-Date: 1444095155 2015/10/06 01:32:35 $ $NHDT-Branch: master $:$NHDT-Revision: 1.183 $ */ +/* NetHack 3.6 mon.c $NHDT-Date: 1445215021 2015/10/19 00:37:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.190 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -659,6 +659,7 @@ movemon() /* reset obj bypasses before next monster moves */ if (context.bypasses) clear_bypasses(); + clear_splitobjs(); if (minliquid(mtmp)) continue; @@ -705,7 +706,10 @@ movemon() /* reset obj bypasses after last monster has moved */ if (context.bypasses) clear_bypasses(); - dmonsfree(); /* remove all dead monsters */ + clear_splitobjs(); + /* remove dead monsters; dead vault guard will be left at <0,0> + if temporary corridor out of vault hasn't been removed yet */ + dmonsfree(); /* a monster may have levteleported player -dlc */ if (u.utotype) {