if a migrating monster was killed off because there was no room on the
destination level, it would leave a corpse even if it was a type
which should never leave one (demon, golem, blob, &c)
+end of game while carrying Schroedinger's Box would reveal cat-or-corpse
+ for inventory disclosure or put that info into dumplog, but not both
Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository
-/* NetHack 3.6 extern.h $NHDT-Date: 1541719965 2018/11/08 23:32:45 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.647 $ */
+/* NetHack 3.6 extern.h $NHDT-Date: 1542798602 2018/11/21 11:10:02 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.650 $ */
/* Copyright (c) Steve Creps, 1988. */
/* NetHack may be freely redistributed. See license for details. */
E int NDECL(encumber_msg);
E int FDECL(container_at, (int, int, BOOLEAN_P));
E int NDECL(doloot);
+E void FDECL(observe_quantum_cat, (struct obj *, BOOLEAN_P, BOOLEAN_P));
E boolean FDECL(container_gone, (int (*)(OBJ_P)));
E boolean NDECL(u_handsy);
E int FDECL(use_container, (struct obj **, int, BOOLEAN_P));
-/* NetHack 3.6 end.c $NHDT-Date: 1541902951 2018/11/11 02:22:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.150 $ */
+/* NetHack 3.6 end.c $NHDT-Date: 1542798619 2018/11/21 11:10:19 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.152 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *, int));
STATIC_DCL void FDECL(artifact_score, (struct obj *, BOOLEAN_P, winid));
STATIC_DCL void FDECL(really_done, (int)) NORETURN;
-STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int));
STATIC_DCL void FDECL(savelife, (int));
STATIC_PTR int FDECL(CFDECLSPEC vanqsort_cmp, (const genericptr,
const genericptr));
return;
}
+#if 0
+/*
+ * odds_and_ends() was used for 3.6.0 and 3.6.1.
+ * Schroedinger's Cat is handled differently starting with 3.6.2.
+ */
+STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int));
+
#define CAT_CHECK 2
STATIC_OVL boolean
int what;
{
struct obj *otmp;
+
for (otmp = list; otmp; otmp = otmp->nobj) {
switch (what) {
case CAT_CHECK: /* Schroedinger's Cat */
}
return FALSE;
}
+#endif
/* called twice; first to calculate total, then to list relevant items */
STATIC_OVL void
obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
if (Is_container(obj) || obj->otyp == STATUE)
obj->cknown = obj->lknown = 1;
+ /* we resolve Schroedinger's cat now in case of both
+ disclosure and dumplog, where the 50:50 chance for
+ live cat has to be the same both times */
+ if (SchroedingersBox(obj)) {
+ if (!Schroedingers_cat) {
+ /* tell observe_quantum_cat() not to create a cat; if it
+ chooses live cat in this situation, it will leave the
+ SchroedingersBox flag set (for container_contents()) */
+ observe_quantum_cat(obj, FALSE, FALSE);
+ if (SchroedingersBox(obj))
+ Schroedingers_cat = TRUE;
+ } else
+ obj->spe = 0; /* ordinary box with cat corpse in it */
+ }
}
if (strcmp(flags.end_disclose, "none"))
/* if pets will contribute to score, populate mydogs list now
(bones creation isn't a factor, but pline() messaging is; used to
- be done ever sooner, but we need it to come after dump_everything()
+ be done even sooner, but we need it to come after dump_everything()
so that any accompanying pets are still on the map during dump) */
if (how == ESCAPED || how == ASCENDED)
keepdogs(TRUE);
viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
mtmp = mydogs;
Strcpy(pbuf, "You");
- if (!Schroedingers_cat) /* check here in case disclosure was off */
- Schroedingers_cat = odds_and_ends(invent, CAT_CHECK);
- if (Schroedingers_cat) {
- int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]);
-
- mhp = d(m_lev, 8);
- nowrap_add(u.urexp, mhp);
- Strcat(eos(pbuf), " and Schroedinger's cat");
- }
- if (mtmp) {
+ if (mtmp || Schroedingers_cat) {
while (mtmp) {
Sprintf(eos(pbuf), " and %s", mon_nam(mtmp));
if (mtmp->mtame)
nowrap_add(u.urexp, mtmp->mhp);
mtmp = mtmp->nmon;
}
+ /* [it might be more robust to create a housecat and add it to
+ mydogs; it doesn't have to be placed on the map for that] */
+ if (Schroedingers_cat) {
+ int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]);
+
+ mhp = d(m_lev, 8);
+ nowrap_add(u.urexp, mhp);
+ Strcat(eos(pbuf), " and Schroedinger's cat");
+ }
dump_forward_putstr(endwin, 0, pbuf, done_stopprint);
pbuf[0] = '\0';
} else {
{
register struct obj *box, *obj;
char buf[BUFSZ];
- boolean cat, deadcat;
+ boolean cat,
+ dumping =
+#ifdef DUMPLOG
+ iflags.in_dumplog ? TRUE :
+#endif
+ FALSE;
for (box = list; box; box = box->nobj) {
if (Is_container(box) || box->otyp == STATUE) {
box->cknown = 1; /* we're looking at the contents now */
if (identified)
box->lknown = 1;
- cat = deadcat = FALSE;
- if (SchroedingersBox(box) && !Schroedingers_cat) {
- /* Schroedinger's Cat? */
- cat = odds_and_ends(box, CAT_CHECK);
- if (cat)
- Schroedingers_cat = TRUE;
- else
- deadcat = TRUE;
- box->spe = 0;
- }
if (box->otyp == BAG_OF_TRICKS) {
continue; /* wrong type of container */
} else if (box->cobj) {
Loot *sortedcobj, *srtc;
unsigned sortflags;
+ /* at this stage, the SchroedingerBox() flag is only set
+ if the cat inside the box is alive; the box actually
+ contains a cat corpse that we'll pretend is not there;
+ for dead cat, the flag will be clear and there'll be
+ a cat corpse inside the box; either way, inventory
+ reports the box as containing "1 item" */
+ cat = SchroedingersBox(box);
+
Sprintf(buf, "Contents of %s:", the(xname(box)));
putstr(tmpwin, 0, buf);
- putstr(tmpwin, 0, "");
- sortflags = (((flags.sortloot == 'l' || flags.sortloot == 'f')
- ? SORTLOOT_LOOT : 0)
- | (flags.sortpack ? SORTLOOT_PACK : 0));
- sortedcobj = sortloot(&box->cobj, sortflags, FALSE,
- (boolean FDECL((*), (OBJ_P))) 0);
- for (srtc = sortedcobj; ((obj = srtc->obj) != 0); ++srtc) {
- if (identified) {
- discover_object(obj->otyp, TRUE, FALSE);
- obj->known = obj->bknown = obj->dknown
- = obj->rknown = 1;
- if (Is_container(obj) || obj->otyp == STATUE)
- obj->cknown = obj->lknown = 1;
+ if (!dumping)
+ putstr(tmpwin, 0, "");
+ buf[0] = buf[1] = ' '; /* two leading spaces */
+ if (box->cobj && !cat) {
+ sortflags = (((flags.sortloot == 'l'
+ || flags.sortloot == 'f')
+ ? SORTLOOT_LOOT : 0)
+ | (flags.sortpack ? SORTLOOT_PACK : 0));
+ sortedcobj = sortloot(&box->cobj, sortflags, FALSE,
+ (boolean FDECL((*), (OBJ_P))) 0);
+ for (srtc = sortedcobj; ((obj = srtc->obj) != 0); ++srtc) {
+ if (identified) {
+ discover_object(obj->otyp, TRUE, FALSE);
+ obj->known = obj->bknown = obj->dknown
+ = obj->rknown = 1;
+ if (Is_container(obj) || obj->otyp == STATUE)
+ obj->cknown = obj->lknown = 1;
+ }
+ Strcpy(&buf[2], doname(obj));
+ putstr(tmpwin, 0, buf);
}
- putstr(tmpwin, 0, doname(obj));
+ unsortloot(&sortedcobj);
+ } else if (cat) {
+ Strcpy(&buf[2], "Schroedinger's cat!");
+ putstr(tmpwin, 0, buf);
}
- unsortloot(&sortedcobj);
- if (cat)
- putstr(tmpwin, 0, "Schroedinger's cat");
- else if (deadcat)
- putstr(tmpwin, 0, "Schroedinger's dead cat");
+ if (dumping)
+ putstr(0, 0, "");
display_nhwindow(tmpwin, TRUE);
destroy_nhwindow(tmpwin);
if (all_containers)
container_contents(box->cobj, identified, TRUE,
reportempty);
- } else if (cat || deadcat) {
- pline("%s Schroedinger's %scat!", Tobjnam(box, "contain"),
- deadcat ? "dead " : "");
- display_nhwindow(WIN_MESSAGE, FALSE);
} else if (reportempty) {
pline("%s is empty.", upstart(thesimpleoname(box)));
display_nhwindow(WIN_MESSAGE, FALSE);
-/* NetHack 3.6 makemon.c $NHDT-Date: 1539804904 2018/10/17 19:35:04 $ $NHDT-Branch: keni-makedefsm $:$NHDT-Revision: 1.127 $ */
+/* NetHack 3.6 makemon.c $NHDT-Date: 1542798623 2018/11/21 11:10:23 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.128 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
if (rn2(2))
(void) mongets(mtmp, rn2(3) ? DAGGER : KNIFE);
if (rn2(5))
- (void) mongets(mtmp, rn2(3) ? LEATHER_JACKET : LEATHER_CLOAK);
+ (void) mongets(mtmp, rn2(3) ? LEATHER_JACKET
+ : LEATHER_CLOAK);
if (rn2(3))
(void) mongets(mtmp, rn2(3) ? LOW_BOOTS : HIGH_BOOTS);
if (rn2(3))
case PM_HUNTER:
(void) mongets(mtmp, rn2(3) ? SHORT_SWORD : DAGGER);
if (rn2(2))
- (void) mongets(mtmp, rn2(2) ? LEATHER_JACKET : LEATHER_ARMOR);
+ (void) mongets(mtmp, rn2(2) ? LEATHER_JACKET
+ : LEATHER_ARMOR);
(void) mongets(mtmp, BOW);
m_initthrow(mtmp, ARROW, 12);
break;
break;
case S_QUANTMECH:
if (!rn2(20)) {
+ struct obj *catcorpse;
+
otmp = mksobj(LARGE_BOX, FALSE, FALSE);
- otmp->spe = 1; /* flag for special box */
- otmp->owt = weight(otmp);
+ /* we used to just set the flag, which resulted in weight()
+ treating the box as being heavier by the weight of a cat;
+ now we include a cat corpse that won't rot; when opening or
+ disclosing the box's contents, the corpse might be revived,
+ otherwise it's given a rot timer; weight is now ordinary */
+ if ((catcorpse = mksobj(CORPSE, TRUE, FALSE)) != 0) {
+ otmp->spe = 1; /* flag for special SchroedingersBox */
+ set_corpsenm(catcorpse, PM_HOUSECAT);
+ (void) stop_timer(ROT_CORPSE, obj_to_any(catcorpse));
+ add_to_container(otmp, catcorpse);
+ otmp->owt = weight(otmp);
+ }
(void) mpickobj(mtmp, otmp);
}
break;
-/* NetHack 3.6 mkobj.c $NHDT-Date: 1518053380 2018/02/08 01:29:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.130 $ */
+/* NetHack 3.6 mkobj.c $NHDT-Date: 1542798624 2018/11/21 11:10:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.136 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Derek S. Ray, 2015. */
/* NetHack may be freely redistributed. See license for details. */
when we assume this is a brand new glob so use objects[].oc_weight */
if (obj->globby && obj->owt > 0)
wt = obj->owt;
- if (SchroedingersBox(obj))
- wt += mons[PM_HOUSECAT].cwt;
if (Is_container(obj) || obj->otyp == STATUE) {
struct obj *contents;
register int cwt = 0;
-/* NetHack 3.6 pickup.c $NHDT-Date: 1541312259 2018/11/04 06:17:39 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.201 $ */
+/* NetHack 3.6 pickup.c $NHDT-Date: 1542798625 2018/11/21 11:10:25 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.202 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
STATIC_PTR int FDECL(out_container, (struct obj *));
STATIC_DCL void FDECL(removed_from_icebox, (struct obj *));
STATIC_DCL long FDECL(mbag_item_gone, (int, struct obj *));
-STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *));
STATIC_DCL void FDECL(explain_container_prompt, (BOOLEAN_P));
STATIC_DCL int FDECL(traditional_loot, (BOOLEAN_P));
STATIC_DCL int FDECL(menu_loot, (int, BOOLEAN_P));
return loss;
}
-STATIC_OVL void
-observe_quantum_cat(box)
+/* used for #loot/apply, #tip, and final disclosure */
+void
+observe_quantum_cat(box, makecat, givemsg)
struct obj *box;
+boolean makecat, givemsg;
{
static NEARDATA const char sc[] = "Schroedinger's Cat";
struct obj *deadcat;
- struct monst *livecat;
+ struct monst *livecat = 0;
xchar ox, oy;
+ boolean itsalive = !rn2(2);
- 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);
+ force the determination of alive vs dead state; but basing it
+ just on opening or disclosing the box is much simpler to cope with */
+
+ /* SchroedingersBox already has a cat corpse in it */
+ deadcat = box->cobj;
+ if (itsalive) {
+ if (makecat)
+ livecat = makemon(&mons[PM_HOUSECAT], box->ox, box->oy,
+ NO_MINVENT | MM_ADJACENTOK);
+ if (livecat) {
+ livecat->mpeaceful = 1;
+ set_malign(livecat);
+ if (givemsg) {
+ 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);
+ if (deadcat) {
+ obj_extract_self(deadcat);
+ obfree(deadcat, (struct obj *) 0), deadcat = 0;
+ }
+ box->owt = weight(box);
+ box->spe = 0;
+ }
} else {
- deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT],
- box->ox, box->oy, sc);
+ box->spe = 0; /* now an ordinary box (with a cat corpse inside) */
if (deadcat) {
- obj_extract_self(deadcat);
- (void) add_to_container(box, deadcat);
+ /* set_corpsenm() will start the rot timer that was removed
+ when makemon() created SchroedingersBox; start it from
+ now rather than from when this special corpse got created */
+ deadcat->age = monstermoves;
+ set_corpsenm(deadcat, PM_HOUSECAT);
+ deadcat = oname(deadcat, sc);
}
- pline_The("%s inside the box is dead!",
- Hallucination ? rndmonnam((char *) 0) : "housecat");
+ if (givemsg)
+ pline_The("%s inside the box is dead!",
+ Hallucination ? rndmonnam((char *) 0) : "housecat");
}
- box->owt = weight(box);
+ nhUse(deadcat);
return;
}
/* check for Schroedinger's Cat */
quantum_cat = SchroedingersBox(current_container);
if (quantum_cat) {
- observe_quantum_cat(current_container);
+ observe_quantum_cat(current_container, TRUE, TRUE);
used = 1;
}
} else if (SchroedingersBox(box)) {
char yourbuf[BUFSZ];
- observe_quantum_cat(box);
+ observe_quantum_cat(box, TRUE, TRUE);
if (!Has_contents(box)) /* evidently a live cat came out */
/* container type of "large box" is inferred */
pline("%sbox is now empty.", Shk_Your(yourbuf, box));
-/* NetHack 3.6 restore.c $NHDT-Date: 1451082255 2015/12/25 22:24:15 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.103 $ */
+/* NetHack 3.6 restore.c $NHDT-Date: 1542798626 2018/11/21 11:10:26 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.109 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2009. */
/* NetHack may be freely redistributed. See license for details. */
/* get contents of a container or statue */
if (Has_contents(otmp)) {
struct obj *otmp3;
+
otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp));
/* restore container back pointers */
for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj)
otmp3->ocontainer = otmp;
+ } else if (SchroedingersBox(otmp)) {
+ struct obj *catcorpse;
+
+ /*
+ * TODO: Remove this after 3.6.x save compatibility is dropped.
+ *
+ * For 3.6.2, SchroedingersBox() always has a cat corpse in it.
+ * For 3.6.[01], it was empty and its weight was falsified
+ * to have the value it would have had if there was one inside.
+ * Put a non-rotting cat corpse in this box to convert to 3.6.2.
+ *
+ * [Note: after this fix up, future save/restore of this object
+ * will take the Has_contents() code path above.]
+ */
+ if ((catcorpse = mksobj(CORPSE, TRUE, FALSE)) != 0) {
+ otmp->spe = 1; /* flag for special SchroedingersBox */
+ set_corpsenm(catcorpse, PM_HOUSECAT);
+ (void) stop_timer(ROT_CORPSE, obj_to_any(catcorpse));
+ add_to_container(otmp, catcorpse);
+ otmp->owt = weight(otmp);
+ }
}
if (otmp->bypass)
otmp->bypass = 0;
-/* NetHack 3.6 zap.c $NHDT-Date: 1537234123 2018/09/18 01:28:43 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.287 $ */
+/* NetHack 3.6 zap.c $NHDT-Date: 1542798627 2018/11/21 11:10:27 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.289 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */
if (Is_container(obj) || obj->otyp == STATUE) {
obj->cknown = obj->lknown = 1;
if (!obj->cobj) {
- boolean catbox = SchroedingersBox(obj);
-
+ pline("%s empty.", Tobjnam(obj, "are"));
+ } else if (SchroedingersBox(obj)) {
/* we don't want to force alive vs dead
determination for Schroedinger's Cat here,
so just make probing be inconclusive for it */
- if (catbox)
- obj->cknown = 0;
- pline("%s empty.", Tobjnam(obj, catbox ? "seem" : "are"));
+ You("aren't sure whether %s has %s or its corpse inside.",
+ the(xname(obj)),
+ /* unfortunately, we can't tell whether rndmonnam()
+ picks a form which can't leave a corpse */
+ an(Hallucination ? rndmonnam((char *) 0) : "cat"));
+ obj->cknown = 0;
} else {
struct obj *o;
/* view contents (not recursively) */