fix #K4006 - 'null obj after quiver merge' panic
Using apply to unlight a lit potion of oil makes it unlit, removes it from inventory, and then re-adds it to try to force it to merge with other potions of oil. If it was wielded and the other potions were quivered, the game would panic. When merging, they get forced into the weapon slot in preference to the quiver slot. Unwearing it before freeinv+addinv would solve this but also leave the hero with nothing wielded, even if it didn't merge with another stack. Instead, don't try to merge if the potion being unlit happens to be worn. 3.6.x was subject to this too and the fix is small+isolated but the situation is so uncommon that I haven't bothered backporting it. Applying a lump of royal jelly and then not picking anything to rub it on had a similar problem. It also panicked if the applied lump was wielded and other lumps were quivered. The fix is different because the stack it gets split from during apply is known. This one doesn't impact 3.6.x; applying jelly to eggs wasn't implemented yet.
This commit is contained in:
30
src/apply.c
30
src/apply.c
@@ -1684,10 +1684,14 @@ light_cocktail(struct obj **optr)
|
||||
/*
|
||||
* Free & add to re-merge potion. This will average the
|
||||
* age of the potions. Not exactly the best solution,
|
||||
* but its easy.
|
||||
* but its easy. Don't do that unless obj is not worn (uwep,
|
||||
* uswapwep, or uquiver) because if wielded and other oil is
|
||||
* quivered a "null obj after quiver merge" panic will occur.
|
||||
*/
|
||||
freeinv(obj);
|
||||
*optr = addinv(obj);
|
||||
if (!obj->owornmask) {
|
||||
freeinv(obj);
|
||||
*optr = addinv(obj);
|
||||
}
|
||||
return;
|
||||
} else if (Underwater) {
|
||||
There("is not enough oxygen to sustain a fire.");
|
||||
@@ -1702,7 +1706,8 @@ light_cocktail(struct obj **optr)
|
||||
Blind ? "" : " It gives off a dim light.");
|
||||
|
||||
if (obj->unpaid && costly_spot(u.ux, u.uy)) {
|
||||
struct monst *shkp VOICEONLY = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
|
||||
struct monst *shkp VOICEONLY = shop_keeper(*in_rooms(u.ux, u.uy,
|
||||
SHOPBASE));
|
||||
|
||||
/* Normally, we shouldn't both partially and fully charge
|
||||
* for an item, but (Yendorian Fuel) Taxes are inevitable...
|
||||
@@ -3477,10 +3482,10 @@ use_royal_jelly(struct obj **optr)
|
||||
{
|
||||
int oldcorpsenm;
|
||||
unsigned was_timed;
|
||||
struct obj *obj = *optr;
|
||||
struct obj *eobj;
|
||||
struct obj *eobj, *obj = *optr;
|
||||
boolean splitit = (obj->quan > 1L);
|
||||
|
||||
if (obj->quan > 1L)
|
||||
if (splitit)
|
||||
obj = splitobj(obj, 1L);
|
||||
/* remove from inventory so that it won't be offered as a choice
|
||||
to rub on itself */
|
||||
@@ -3489,8 +3494,15 @@ use_royal_jelly(struct obj **optr)
|
||||
/* right now you can rub one royal jelly on an entire stack of eggs */
|
||||
eobj = getobj("rub the royal jelly on", jelly_ok, GETOBJ_PROMPT);
|
||||
if (!eobj) {
|
||||
addinv(obj); /* put the unused lump back; if it came from
|
||||
* a split, it should merge back */
|
||||
if (splitit) {
|
||||
(void) unsplitobj(obj);
|
||||
update_inventory(); /* freeinv() updated perminv w/ obj omitted */
|
||||
} else {
|
||||
/* this lump was already separate; pervent merge */
|
||||
obj->nomerge = 1;
|
||||
addinv(obj); /* put the unused lump back; updates perminv */
|
||||
obj->nomerge = 0;
|
||||
}
|
||||
return ECMD_CANCEL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1583,7 +1583,9 @@ nhl_gamestate(lua_State *L)
|
||||
wornmask = otmp->owornmask;
|
||||
otmp->owornmask = 0L;
|
||||
extract_nobj(otmp, &gmst_invent);
|
||||
otmp->nomerge = 1;
|
||||
addinv(otmp);
|
||||
otmp->nomerge = 0;
|
||||
if (wornmask)
|
||||
setworn(otmp, wornmask);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user