fix #H6104 - no potion handling in thitu()
thitu() is mostly used for arrows and darts "thrown" by traps, but scatter() uses it on items launched by a land mine explosion. Traps had no need for potion handling, but scattering does. Changing thitu() to call potionhit() required that more information be passed to the latter in case killer reason was needed, and thitu()'s callers needed to be updated since it now might use up its missile (only when that's a potion, so scatter() is only caller which actually needed to care). Quite a bit of work--especially the testing--for something which will never be noticed in actual play. In hindsight, it would have been much simpler just to make scatter destroy all potions rather than allow the 1% chance of remaining intact (via obj_resists()), or else leave any intact ones at the explosion spot instead of launching them.
This commit is contained in:
@@ -2786,9 +2786,8 @@ struct obj *obj;
|
||||
int hitu, hitvalu;
|
||||
|
||||
hitvalu = 8 + otmp->spe;
|
||||
hitu = thitu(hitvalu,
|
||||
dmgval(otmp, &youmonst),
|
||||
otmp, (char *)0);
|
||||
hitu = thitu(hitvalu, dmgval(otmp, &youmonst),
|
||||
&otmp, (char *)0);
|
||||
if (hitu) {
|
||||
pline_The("%s hits you as you try to snatch it!",
|
||||
the(onambuf));
|
||||
|
||||
@@ -884,7 +884,7 @@ boolean hitsroof;
|
||||
/* object now hits you */
|
||||
|
||||
if (obj->oclass == POTION_CLASS) {
|
||||
potionhit(&youmonst, obj, TRUE);
|
||||
potionhit(&youmonst, obj, POTHIT_HERO_THROW);
|
||||
} else if (breaktest(obj)) {
|
||||
int otyp = obj->otyp;
|
||||
int blindinc;
|
||||
@@ -1086,7 +1086,7 @@ boolean
|
||||
&& rn2(6)) {
|
||||
/* alternative to prayer or wand of opening/spell of knock
|
||||
for dealing with cursed saddle: throw holy water > */
|
||||
potionhit(u.usteed, obj, TRUE);
|
||||
potionhit(u.usteed, obj, POTHIT_HERO_THROW);
|
||||
} else {
|
||||
hitfloor(obj);
|
||||
}
|
||||
@@ -1614,7 +1614,7 @@ register struct obj *obj; /* thrownobj or kickedobj or uwep */
|
||||
|
||||
} else if (obj->oclass == POTION_CLASS
|
||||
&& (guaranteed_hit || ACURR(A_DEX) > rnd(25))) {
|
||||
potionhit(mon, obj, TRUE);
|
||||
potionhit(mon, obj, POTHIT_HERO_THROW);
|
||||
return 1;
|
||||
|
||||
} else if (befriend_with_obj(mon->data, obj)
|
||||
|
||||
@@ -570,7 +570,7 @@ struct obj *obj; /* only scatter this obj */
|
||||
struct scatter_chain *schain = (struct scatter_chain *) 0;
|
||||
long total = 0L;
|
||||
|
||||
while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) {
|
||||
while ((otmp = (individual_object ? obj : level.objects[sx][sy])) != 0) {
|
||||
if (otmp->quan > 1L) {
|
||||
qtmp = otmp->quan - 1L;
|
||||
if (qtmp > LARGEST_INT)
|
||||
@@ -584,8 +584,8 @@ struct obj *obj; /* only scatter this obj */
|
||||
used_up = FALSE;
|
||||
|
||||
/* 9 in 10 chance of fracturing boulders or statues */
|
||||
if ((scflags & MAY_FRACTURE)
|
||||
&& ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))
|
||||
if ((scflags & MAY_FRACTURE) != 0
|
||||
&& (otmp->otyp == BOULDER || otmp->otyp == STATUE)
|
||||
&& rn2(10)) {
|
||||
if (otmp->otyp == BOULDER) {
|
||||
if (cansee(sx, sy))
|
||||
@@ -614,7 +614,7 @@ struct obj *obj; /* only scatter this obj */
|
||||
used_up = TRUE;
|
||||
|
||||
/* 1 in 10 chance of destruction of obj; glass, egg destruction */
|
||||
} else if ((scflags & MAY_DESTROY)
|
||||
} else if ((scflags & MAY_DESTROY) != 0
|
||||
&& (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS
|
||||
|| otmp->otyp == EGG))) {
|
||||
if (breaks(otmp, (xchar) sx, (xchar) sy))
|
||||
@@ -622,8 +622,7 @@ struct obj *obj; /* only scatter this obj */
|
||||
}
|
||||
|
||||
if (!used_up) {
|
||||
stmp = (struct scatter_chain *)
|
||||
alloc(sizeof (struct scatter_chain));
|
||||
stmp = (struct scatter_chain *) alloc(sizeof *stmp);
|
||||
stmp->next = (struct scatter_chain *) 0;
|
||||
stmp->obj = otmp;
|
||||
stmp->ox = sx;
|
||||
@@ -679,7 +678,9 @@ struct obj *obj; /* only scatter this obj */
|
||||
if (bigmonst(youmonst.data))
|
||||
hitvalu++;
|
||||
hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst),
|
||||
stmp->obj, (char *) 0);
|
||||
&stmp->obj, (char *) 0);
|
||||
if (!stmp->obj)
|
||||
stmp->stopped = TRUE;
|
||||
if (hitu) {
|
||||
stmp->range -= 3;
|
||||
stop_occupation();
|
||||
|
||||
@@ -29,11 +29,12 @@ extern boolean notonhead; /* for long worms */
|
||||
|
||||
/* hero is hit by something other than a monster */
|
||||
int
|
||||
thitu(tlev, dam, obj, name)
|
||||
thitu(tlev, dam, objp, name)
|
||||
int tlev, dam;
|
||||
struct obj *obj;
|
||||
const char *name; /* if null, then format `obj' */
|
||||
struct obj **objp;
|
||||
const char *name; /* if null, then format `*objp' */
|
||||
{
|
||||
struct obj *obj = objp ? *objp : 0;
|
||||
const char *onm, *knm;
|
||||
boolean is_acid;
|
||||
int kprefix = KILLED_BY_AN;
|
||||
@@ -42,8 +43,8 @@ const char *name; /* if null, then format `obj' */
|
||||
if (!name) {
|
||||
if (!obj)
|
||||
panic("thitu: name & obj both null?");
|
||||
name =
|
||||
strcpy(onmbuf, (obj->quan > 1L) ? doname(obj) : mshot_xname(obj));
|
||||
name = strcpy(onmbuf,
|
||||
(obj->quan > 1L) ? doname(obj) : mshot_xname(obj));
|
||||
knm = strcpy(knmbuf, killer_xname(obj));
|
||||
kprefix = KILLED_BY; /* killer_name supplies "an" if warranted */
|
||||
} else {
|
||||
@@ -70,14 +71,20 @@ const char *name; /* if null, then format `obj' */
|
||||
else
|
||||
You("are hit by %s%s", onm, exclam(dam));
|
||||
|
||||
if (obj && objects[obj->otyp].oc_material == SILVER && Hate_silver) {
|
||||
/* extra damage already applied by dmgval() */
|
||||
pline_The("silver sears your flesh!");
|
||||
exercise(A_CON, FALSE);
|
||||
}
|
||||
if (is_acid && Acid_resistance) {
|
||||
pline("It doesn't seem to hurt you.");
|
||||
} else if (obj && obj->oclass == POTION_CLASS) {
|
||||
/* an explosion which scatters objects might hit hero with one
|
||||
(potions deliberately thrown at hero are handled by m_throw) */
|
||||
potionhit(&youmonst, obj, POTHIT_OTHER_THROW);
|
||||
*objp = obj = 0; /* potionhit() uses up the potion */
|
||||
} else {
|
||||
if (obj && objects[obj->otyp].oc_material == SILVER
|
||||
&& Hate_silver) {
|
||||
/* extra damage already applied by dmgval() */
|
||||
pline_The("silver sears your flesh!");
|
||||
exercise(A_CON, FALSE);
|
||||
}
|
||||
if (is_acid)
|
||||
pline("It burns!");
|
||||
losehp(dam, knm, kprefix); /* acid damage */
|
||||
@@ -110,9 +117,9 @@ int x, y;
|
||||
else
|
||||
create = 1;
|
||||
|
||||
if (create
|
||||
&& !((mtmp = m_at(x, y)) && (mtmp->mtrapped) && (t = t_at(x, y))
|
||||
&& ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)))) {
|
||||
if (create && !((mtmp = m_at(x, y)) != 0 && mtmp->mtrapped
|
||||
&& (t = t_at(x, y)) != 0
|
||||
&& (t->ttyp == PIT || t->ttyp == SPIKED_PIT))) {
|
||||
int objgone = 0;
|
||||
|
||||
if (down_gate(x, y) != -1)
|
||||
@@ -329,7 +336,9 @@ boolean verbose; /* give message(s) even when you can't see what happened */
|
||||
mtmp->msleeping = 0;
|
||||
if (vis)
|
||||
otmp->dknown = 1;
|
||||
potionhit(mtmp, otmp, FALSE);
|
||||
/* probably thrown by a monster rather than 'other', but the
|
||||
distinction only matters when hitting the hero */
|
||||
potionhit(mtmp, otmp, POTHIT_OTHER_THROW);
|
||||
return 1;
|
||||
} else {
|
||||
damage = dmgval(otmp, mtmp);
|
||||
@@ -549,7 +558,7 @@ struct obj *obj; /* missile (or stack providing it) */
|
||||
if (singleobj->oclass == POTION_CLASS) {
|
||||
if (!Blind)
|
||||
singleobj->dknown = 1;
|
||||
potionhit(&youmonst, singleobj, FALSE);
|
||||
potionhit(&youmonst, singleobj, POTHIT_MONST_THROW);
|
||||
break;
|
||||
}
|
||||
oldumort = u.umortality;
|
||||
@@ -565,7 +574,7 @@ struct obj *obj; /* missile (or stack providing it) */
|
||||
/* fall through */
|
||||
case CREAM_PIE:
|
||||
case BLINDING_VENOM:
|
||||
hitu = thitu(8, 0, singleobj, (char *) 0);
|
||||
hitu = thitu(8, 0, &singleobj, (char *) 0);
|
||||
break;
|
||||
default:
|
||||
dam = dmgval(singleobj, &youmonst);
|
||||
@@ -585,7 +594,7 @@ struct obj *obj; /* missile (or stack providing it) */
|
||||
hitv += 8 + singleobj->spe;
|
||||
if (dam < 1)
|
||||
dam = 1;
|
||||
hitu = thitu(hitv, dam, singleobj, (char *) 0);
|
||||
hitu = thitu(hitv, dam, &singleobj, (char *) 0);
|
||||
}
|
||||
if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) {
|
||||
char onmbuf[BUFSZ], knmbuf[BUFSZ];
|
||||
@@ -888,7 +897,7 @@ struct monst *mtmp;
|
||||
if (dam < 1)
|
||||
dam = 1;
|
||||
|
||||
(void) thitu(hitv, dam, otmp, (char *) 0);
|
||||
(void) thitu(hitv, dam, &otmp, (char *) 0);
|
||||
stop_occupation();
|
||||
return;
|
||||
}
|
||||
|
||||
17
src/potion.c
17
src/potion.c
@@ -1243,24 +1243,28 @@ const char *objphrase; /* "Your widget glows" or "Steed's saddle glows" */
|
||||
return res;
|
||||
}
|
||||
|
||||
/* potion obj hits monster mon, which might be youmounst; obj always use up */
|
||||
void
|
||||
potionhit(mon, obj, your_fault)
|
||||
register struct monst *mon;
|
||||
register struct obj *obj;
|
||||
boolean your_fault;
|
||||
potionhit(mon, obj, how)
|
||||
struct monst *mon;
|
||||
struct obj *obj;
|
||||
int how;
|
||||
{
|
||||
const char *botlnam = bottlename();
|
||||
boolean isyou = (mon == &youmonst);
|
||||
int distance, tx, ty;
|
||||
struct obj *saddle = (struct obj *) 0;
|
||||
boolean hit_saddle = FALSE;
|
||||
boolean hit_saddle = FALSE, your_fault = (how <= POTHIT_HERO_THROW);
|
||||
|
||||
if (isyou) {
|
||||
tx = u.ux, ty = u.uy;
|
||||
distance = 0;
|
||||
pline_The("%s crashes on your %s and breaks into shards.", botlnam,
|
||||
body_part(HEAD));
|
||||
losehp(Maybe_Half_Phys(rnd(2)), "thrown potion", KILLED_BY_AN);
|
||||
losehp(Maybe_Half_Phys(rnd(2)),
|
||||
(how == POTHIT_OTHER_THROW) ? "propelled potion" /* scatter */
|
||||
: "thrown potion",
|
||||
KILLED_BY_AN);
|
||||
} else {
|
||||
tx = mon->mx, ty = mon->my;
|
||||
/* sometimes it hits the saddle */
|
||||
@@ -1314,6 +1318,7 @@ boolean your_fault;
|
||||
case POT_ACID:
|
||||
if (!Acid_resistance) {
|
||||
int dmg;
|
||||
|
||||
pline("This burns%s!",
|
||||
obj->blessed ? " a little"
|
||||
: obj->cursed ? " a lot" : "");
|
||||
|
||||
25
src/trap.c
25
src/trap.c
@@ -844,7 +844,7 @@ register struct trap *trap;
|
||||
unsigned trflags;
|
||||
{
|
||||
register int ttype = trap->ttyp;
|
||||
register struct obj *otmp;
|
||||
struct obj *otmp;
|
||||
boolean already_seen = trap->tseen,
|
||||
forcetrap = (trflags & FORCETRAP) != 0,
|
||||
webmsgok = (trflags & NOWEBMSG) == 0,
|
||||
@@ -915,8 +915,9 @@ unsigned trflags;
|
||||
otmp->opoisoned = 0;
|
||||
if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { /* nothing */
|
||||
;
|
||||
} else if (thitu(8, dmgval(otmp, &youmonst), otmp, "arrow")) {
|
||||
obfree(otmp, (struct obj *) 0);
|
||||
} else if (thitu(8, dmgval(otmp, &youmonst), &otmp, "arrow")) {
|
||||
if (otmp)
|
||||
obfree(otmp, (struct obj *) 0);
|
||||
} else {
|
||||
place_object(otmp, u.ux, u.uy);
|
||||
if (!Blind)
|
||||
@@ -944,13 +945,15 @@ unsigned trflags;
|
||||
oldumort = u.umortality;
|
||||
if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { /* nothing */
|
||||
;
|
||||
} else if (thitu(7, dmgval(otmp, &youmonst), otmp, "little dart")) {
|
||||
if (otmp->opoisoned)
|
||||
poisoned("dart", A_CON, "little dart",
|
||||
/* if damage triggered life-saving,
|
||||
poison is limited to attrib loss */
|
||||
(u.umortality > oldumort) ? 0 : 10, TRUE);
|
||||
obfree(otmp, (struct obj *) 0);
|
||||
} else if (thitu(7, dmgval(otmp, &youmonst), &otmp, "little dart")) {
|
||||
if (otmp) {
|
||||
if (otmp->opoisoned)
|
||||
poisoned("dart", A_CON, "little dart",
|
||||
/* if damage triggered life-saving,
|
||||
poison is limited to attrib loss */
|
||||
(u.umortality > oldumort) ? 0 : 10, TRUE);
|
||||
obfree(otmp, (struct obj *) 0);
|
||||
}
|
||||
} else {
|
||||
place_object(otmp, u.ux, u.uy);
|
||||
if (!Blind)
|
||||
@@ -1802,7 +1805,7 @@ int style;
|
||||
if (multi)
|
||||
nomul(0);
|
||||
if (thitu(9 + singleobj->spe, dmgval(singleobj, &youmonst),
|
||||
singleobj, (char *) 0))
|
||||
&singleobj, (char *) 0))
|
||||
stop_occupation();
|
||||
}
|
||||
if (style == ROLL) {
|
||||
|
||||
@@ -731,7 +731,8 @@ int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
|
||||
else
|
||||
setuwep((struct obj *) 0);
|
||||
freeinv(obj);
|
||||
potionhit(mon, obj, TRUE);
|
||||
potionhit(mon, obj,
|
||||
hand_to_hand ? POTHIT_HERO_BASH : POTHIT_HERO_THROW);
|
||||
if (mon->mhp <= 0)
|
||||
return FALSE; /* killed */
|
||||
hittxt = TRUE;
|
||||
|
||||
@@ -3429,7 +3429,7 @@ int dx, dy;
|
||||
if (bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
|
||||
if (Fumbling || rn2(20) >= ACURR(A_DEX)) {
|
||||
/* we hit ourselves */
|
||||
(void) thitu(10 + obj->spe, dmgval(obj, &youmonst), obj,
|
||||
(void) thitu(10 + obj->spe, dmgval(obj, &youmonst), &obj,
|
||||
"boomerang");
|
||||
endmultishot(TRUE);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user