mksobj failure
If mksobj() was told to initialize the object it's creating and the object class was something it didn't understand, it would issue a warning and return Null. But an unknown object class is a severe internal error and very few callers were prepared to deal with a Null result, so change mksobj() to panic instead. Also eliminate the few attempts to deal with Null result that are present in mkobj.c; I didn't go looking elsewhere.
This commit is contained in:
126
src/mkobj.c
126
src/mkobj.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.6 mkobj.c $NHDT-Date: 1570569798 2019/10/08 21:23:18 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.153 $ */
|
||||
/* NetHack 3.6 mkobj.c $NHDT-Date: 1570754586 2019/10/11 00:43:06 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.154 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/*-Copyright (c) Derek S. Ray, 2015. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
@@ -235,15 +235,14 @@ boolean init, artif;
|
||||
struct obj *otmp;
|
||||
|
||||
otmp = mksobj(otyp, init, artif);
|
||||
if (otmp) {
|
||||
add_to_migration(otmp);
|
||||
otmp->owornmask = (long) MIGR_TO_SPECIES;
|
||||
otmp->corpsenm = mflags2;
|
||||
}
|
||||
add_to_migration(otmp);
|
||||
otmp->owornmask = (long) MIGR_TO_SPECIES;
|
||||
otmp->corpsenm = mflags2;
|
||||
return otmp;
|
||||
}
|
||||
|
||||
/* mkobj(): select a type of item from a class, use mksobj() to create it */
|
||||
/* mkobj(): select a type of item from a class, use mksobj() to create it;
|
||||
result is always non-Null */
|
||||
struct obj *
|
||||
mkobj(oclass, artif)
|
||||
char oclass;
|
||||
@@ -309,8 +308,7 @@ struct obj *box;
|
||||
|
||||
for (n = rn2(n + 1); n > 0; n--) {
|
||||
if (box->otyp == ICE_BOX) {
|
||||
if (!(otmp = mksobj(CORPSE, TRUE, TRUE)))
|
||||
continue;
|
||||
otmp = mksobj(CORPSE, TRUE, TRUE);
|
||||
/* Note: setting age to 0 is correct. Age has a different
|
||||
* from usual meaning for objects stored in ice boxes. -KAA
|
||||
*/
|
||||
@@ -768,7 +766,7 @@ static const char dknowns[] = { WAND_CLASS, RING_CLASS, POTION_CLASS,
|
||||
SCROLL_CLASS, GEM_CLASS, SPBOOK_CLASS,
|
||||
WEAPON_CLASS, TOOL_CLASS, 0 };
|
||||
|
||||
/* mksobj(): create a specific type of object */
|
||||
/* mksobj(): create a specific type of object; result it always non-Null */
|
||||
struct obj *
|
||||
mksobj(otyp, init, artif)
|
||||
int otyp;
|
||||
@@ -1062,10 +1060,12 @@ boolean artif;
|
||||
case COIN_CLASS:
|
||||
break; /* do nothing */
|
||||
default:
|
||||
impossible("impossible mkobj %d, sym '%c'.", otmp->otyp,
|
||||
objects[otmp->otyp].oc_class);
|
||||
dealloc_obj(otmp); /* free() would suffice here */
|
||||
return (struct obj *) 0;
|
||||
/* 3.6.3: this used to be impossible() followed by return 0
|
||||
but most callers aren't prepared to deal with Null result
|
||||
and cluttering them up to do so is pointless */
|
||||
panic("mksobj tried to make type %d, class %d.",
|
||||
(int) otmp->otyp, (int) objects[otmp->otyp].oc_class);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1473,6 +1473,7 @@ register struct obj *obj;
|
||||
|
||||
static int treefruits[] = { APPLE, ORANGE, PEAR, BANANA, EUCALYPTUS_LEAF };
|
||||
|
||||
/* called when a tree is kicked; never returns Null */
|
||||
struct obj *
|
||||
rnd_treefruit_at(x, y)
|
||||
int x, y;
|
||||
@@ -1480,15 +1481,17 @@ int x, y;
|
||||
return mksobj_at(treefruits[rn2(SIZE(treefruits))], x, y, TRUE, FALSE);
|
||||
}
|
||||
|
||||
/* create a stack of N gold pieces; never returns Null */
|
||||
struct obj *
|
||||
mkgold(amount, x, y)
|
||||
long amount;
|
||||
int x, y;
|
||||
{
|
||||
register struct obj *gold = g_at(x, y);
|
||||
struct obj *gold = g_at(x, y);
|
||||
|
||||
if (amount <= 0L) {
|
||||
long mul = rnd(30 / max(12-depth(&u.uz), 2));
|
||||
|
||||
amount = (long) (1 + rnd(level_difficulty() + 2) * mul);
|
||||
}
|
||||
if (gold) {
|
||||
@@ -1501,12 +1504,14 @@ int x, y;
|
||||
return gold;
|
||||
}
|
||||
|
||||
/* return TRUE if the corpse has special timing */
|
||||
#define special_corpse(num) \
|
||||
(((num) == PM_LIZARD) || ((num) == PM_LICHEN) || (is_rider(&mons[num])) \
|
||||
|| (mons[num].mlet == S_TROLL))
|
||||
/* return TRUE if the corpse has special timing;
|
||||
lizards and lichen don't rot, trolls and Riders auto-revive */
|
||||
#define special_corpse(num) \
|
||||
(((num) == PM_LIZARD || (num) == PM_LICHEN) \
|
||||
|| (mons[num].mlet == S_TROLL || is_rider(&mons[num])))
|
||||
|
||||
/*
|
||||
/* mkcorpstat: make a corpse or statue; never returns Null.
|
||||
*
|
||||
* OEXTRA note: Passing mtmp causes mtraits to be saved
|
||||
* even if ptr passed as well, but ptr is always used for
|
||||
* the corpse type (corpsenm). That allows the corpse type
|
||||
@@ -1523,40 +1528,37 @@ struct permonst *ptr;
|
||||
int x, y;
|
||||
unsigned corpstatflags;
|
||||
{
|
||||
register struct obj *otmp;
|
||||
struct obj *otmp;
|
||||
boolean init = ((corpstatflags & CORPSTAT_INIT) != 0);
|
||||
|
||||
if (objtype != CORPSE && objtype != STATUE)
|
||||
impossible("making corpstat type %d", objtype);
|
||||
if (x == 0 && y == 0) { /* special case - random placement */
|
||||
otmp = mksobj(objtype, init, FALSE);
|
||||
if (otmp)
|
||||
(void) rloco(otmp);
|
||||
} else
|
||||
(void) rloco(otmp);
|
||||
} else {
|
||||
otmp = mksobj_at(objtype, x, y, init, FALSE);
|
||||
if (otmp) {
|
||||
if (mtmp) {
|
||||
struct obj *otmp2;
|
||||
}
|
||||
|
||||
if (!ptr)
|
||||
ptr = mtmp->data;
|
||||
/* save_mtraits frees original data pointed to by otmp */
|
||||
otmp2 = save_mtraits(otmp, mtmp);
|
||||
if (otmp2)
|
||||
otmp = otmp2;
|
||||
}
|
||||
/* use the corpse or statue produced by mksobj() as-is
|
||||
unless `ptr' is non-null */
|
||||
if (ptr) {
|
||||
int old_corpsenm = otmp->corpsenm;
|
||||
/* when 'mtmp' is non-null make a corpse or statue of that monster,
|
||||
otherwise keep the random type chosen by mksobj() */
|
||||
if (mtmp) {
|
||||
int old_corpsenm = otmp->corpsenm;
|
||||
|
||||
otmp->corpsenm = monsndx(ptr);
|
||||
otmp->owt = weight(otmp);
|
||||
if (otmp->otyp == CORPSE && (special_corpse(old_corpsenm)
|
||||
|| special_corpse(otmp->corpsenm))) {
|
||||
obj_stop_timers(otmp);
|
||||
start_corpse_timeout(otmp);
|
||||
}
|
||||
/* save_mtraits updates otmp->oextra->omonst in place */
|
||||
(void) save_mtraits(otmp, mtmp);
|
||||
|
||||
/* when 'ptr' is non-null use the type specified by our caller,
|
||||
otherwise use the monster's species for the corpse */
|
||||
if (!ptr)
|
||||
ptr = mtmp->data;
|
||||
|
||||
otmp->corpsenm = monsndx(ptr);
|
||||
otmp->owt = weight(otmp);
|
||||
if (otmp->otyp == CORPSE && (special_corpse(old_corpsenm)
|
||||
|| special_corpse(otmp->corpsenm))) {
|
||||
obj_stop_timers(otmp);
|
||||
start_corpse_timeout(otmp);
|
||||
}
|
||||
}
|
||||
return otmp;
|
||||
@@ -1574,15 +1576,14 @@ int
|
||||
corpse_revive_type(obj)
|
||||
struct obj *obj;
|
||||
{
|
||||
int revivetype;
|
||||
int revivetype = obj->corpsenm;
|
||||
struct monst *mtmp;
|
||||
if (has_omonst(obj)
|
||||
&& ((mtmp = get_mtraits(obj, FALSE)) != (struct monst *) 0)) {
|
||||
|
||||
if (has_omonst(obj) && ((mtmp = get_mtraits(obj, FALSE)) != 0)) {
|
||||
/* mtmp is a temporary pointer to a monster's stored
|
||||
attributes, not a real monster */
|
||||
revivetype = mtmp->mnum;
|
||||
} else
|
||||
revivetype = obj->corpsenm;
|
||||
}
|
||||
return revivetype;
|
||||
}
|
||||
|
||||
@@ -1658,26 +1659,29 @@ boolean copyof;
|
||||
return mnew;
|
||||
}
|
||||
|
||||
/* make an object named after someone listed in the scoreboard file */
|
||||
/* make an object named after someone listed in the scoreboard file;
|
||||
never returns Null */
|
||||
struct obj *
|
||||
mk_tt_object(objtype, x, y)
|
||||
int objtype; /* CORPSE or STATUE */
|
||||
register int x, y;
|
||||
int x, y;
|
||||
{
|
||||
register struct obj *otmp, *otmp2;
|
||||
struct obj *otmp;
|
||||
boolean initialize_it;
|
||||
|
||||
/* player statues never contain books */
|
||||
initialize_it = (objtype != STATUE);
|
||||
if ((otmp = mksobj_at(objtype, x, y, initialize_it, FALSE)) != 0) {
|
||||
/* tt_oname will return null if the scoreboard is empty */
|
||||
if ((otmp2 = tt_oname(otmp)) != 0)
|
||||
otmp = otmp2;
|
||||
}
|
||||
otmp = mksobj_at(objtype, x, y, initialize_it, FALSE);
|
||||
/* tt_oname() will return null if the scoreboard is empty;
|
||||
assigning an object name used to allocate a new obj but
|
||||
doesn't any more so we can safely ignore the return value */
|
||||
(void) tt_oname(otmp);
|
||||
|
||||
return otmp;
|
||||
}
|
||||
|
||||
/* make a new corpse or statue, uninitialized if a statue (i.e. no books) */
|
||||
/* make a new corpse or statue, uninitialized if a statue (i.e. no books);
|
||||
never returns Null */
|
||||
struct obj *
|
||||
mk_named_object(objtype, ptr, x, y, nm)
|
||||
int objtype; /* CORPSE or STATUE */
|
||||
@@ -1686,8 +1690,8 @@ int x, y;
|
||||
const char *nm;
|
||||
{
|
||||
struct obj *otmp;
|
||||
unsigned corpstatflags =
|
||||
(objtype != STATUE) ? CORPSTAT_INIT : CORPSTAT_NONE;
|
||||
unsigned corpstatflags = (objtype != STATUE) ? CORPSTAT_INIT
|
||||
: CORPSTAT_NONE;
|
||||
|
||||
otmp = mkcorpstat(objtype, (struct monst *) 0, ptr, x, y, corpstatflags);
|
||||
if (nm)
|
||||
|
||||
Reference in New Issue
Block a user