Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

825 lines (745 sloc) 22.863 kb
/* SCCS Id: @(#)mthrowu.c 3.4 2003/05/09 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
STATIC_DCL int FDECL(drop_throw,(struct obj *,BOOLEAN_P,int,int));
#define URETREATING(x,y) (distmin(u.ux,u.uy,x,y) > distmin(u.ux0,u.uy0,x,y))
#define POLE_LIM 5 /* How far monsters can use pole-weapons */
#ifndef OVLB
STATIC_DCL const char *breathwep[];
#else /* OVLB */
/*
* Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
*/
STATIC_OVL NEARDATA const char *breathwep[] = {
"fragments",
"fire",
"frost",
"sleep gas",
"a disintegration blast",
"lightning",
"poison gas",
"acid",
"strange breath #8",
"strange breath #9"
};
/* hero is hit by something other than a monster */
int
thitu(tlev, dam, obj, name)
int tlev, dam;
struct obj *obj;
const char *name; /* if null, then format `obj' */
{
const char *onm, *knm;
boolean is_acid;
int kprefix = KILLED_BY_AN;
char onmbuf[BUFSZ], knmbuf[BUFSZ];
if (!name) {
if (!obj) panic("thitu: name & obj both null?");
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 {
knm = name;
/* [perhaps ought to check for plural here to] */
if (!strncmpi(name, "the ", 4) ||
!strncmpi(name, "an ", 3) ||
!strncmpi(name, "a ", 2)) kprefix = KILLED_BY;
}
onm = (obj && obj_is_pname(obj)) ? the(name) :
(obj && obj->quan > 1L) ? name : an(name);
is_acid = (obj && obj->otyp == ACID_VENOM);
if(u.uac + tlev <= rnd(20)) {
if(Blind || !flags.verbose) pline("It misses.");
else You("are almost hit by %s.", onm);
return(0);
} else {
if(Blind || !flags.verbose) You("are hit!");
else You("are hit by %s%s", onm, exclam(dam));
if (obj && objects[obj->otyp].oc_material == SILVER
&& hates_silver(youmonst.data)) {
dam += rnd(20);
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 (is_acid) pline("It burns!");
if (Half_physical_damage) dam = (dam+1) / 2;
losehp(dam, knm, kprefix);
exercise(A_STR, FALSE);
}
return(1);
}
}
/* Be sure this corresponds with what happens to player-thrown objects in
* dothrow.c (for consistency). --KAA
* Returns 0 if object still exists (not destroyed).
*/
STATIC_OVL int
drop_throw(obj, ohit, x, y)
register struct obj *obj;
boolean ohit;
int x,y;
{
int retvalu = 1;
int create;
struct monst *mtmp;
struct trap *t;
if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS ||
(ohit && obj->otyp == EGG))
create = 0;
else if (ohit && (is_multigen(obj) || obj->otyp == ROCK))
create = !rn2(3);
else create = 1;
if (create && !((mtmp = m_at(x, y)) && (mtmp->mtrapped) &&
(t = t_at(x, y)) && ((t->ttyp == PIT) ||
(t->ttyp == SPIKED_PIT)))) {
int objgone = 0;
if (down_gate(x, y) != -1)
objgone = ship_object(obj, x, y, FALSE);
if (!objgone) {
if (!flooreffects(obj,x,y,"fall")) { /* don't double-dip on damage */
place_object(obj, x, y);
if (!mtmp && x == u.ux && y == u.uy)
mtmp = &youmonst;
if (mtmp && ohit)
passive_obj(mtmp, obj, (struct attack *)0);
stackobj(obj);
retvalu = 0;
}
}
} else obfree(obj, (struct obj*) 0);
return retvalu;
}
#endif /* OVLB */
#ifdef OVL1
/* an object launched by someone/thing other than player attacks a monster;
return 1 if the object has stopped moving (hit or its range used up) */
int
ohitmon(mtmp, otmp, range, verbose)
struct monst *mtmp; /* accidental target */
struct obj *otmp; /* missile; might be destroyed by drop_throw */
int range; /* how much farther will object travel if it misses */
/* Use -1 to signify to keep going even after hit, */
/* unless its gone (used for rolling_boulder_traps) */
boolean verbose; /* give message(s) even when you can't see what happened */
{
int damage, tmp;
boolean vis, ismimic;
int objgone = 1;
ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER;
vis = cansee(bhitpos.x, bhitpos.y);
tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
if (tmp < rnd(20)) {
if (!ismimic) {
if (vis) miss(distant_name(otmp, mshot_xname), mtmp);
else if (verbose) pline("It is missed.");
}
if (!range) { /* Last position; object drops */
(void) drop_throw(otmp, 0, mtmp->mx, mtmp->my);
return 1;
}
} else if (otmp->oclass == POTION_CLASS) {
if (ismimic) seemimic(mtmp);
mtmp->msleeping = 0;
if (vis) otmp->dknown = 1;
potionhit(mtmp, otmp, FALSE);
return 1;
} else {
damage = dmgval(otmp, mtmp);
if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
damage = 0;
if (ismimic) seemimic(mtmp);
mtmp->msleeping = 0;
if (vis) hit(distant_name(otmp,mshot_xname), mtmp, exclam(damage));
else if (verbose) pline("%s is hit%s", Monnam(mtmp), exclam(damage));
if (otmp->opoisoned && is_poisonable(otmp)) {
if (resists_poison(mtmp)) {
if (vis) pline_The("poison doesn't seem to affect %s.",
mon_nam(mtmp));
} else {
if (rn2(30)) {
damage += rnd(6);
} else {
if (vis) pline_The("poison was deadly...");
damage = mtmp->mhp;
}
}
}
if (objects[otmp->otyp].oc_material == SILVER &&
hates_silver(mtmp->data)) {
if (vis) pline_The("silver sears %s flesh!",
s_suffix(mon_nam(mtmp)));
else if (verbose) pline("Its flesh is seared!");
}
if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx,mtmp->my)) {
if (resists_acid(mtmp)) {
if (vis || verbose)
pline("%s is unaffected.", Monnam(mtmp));
damage = 0;
} else {
if (vis) pline_The("acid burns %s!", mon_nam(mtmp));
else if (verbose) pline("It is burned!");
}
}
mtmp->mhp -= damage;
if (mtmp->mhp < 1) {
if (vis || verbose)
pline("%s is %s!", Monnam(mtmp),
(nonliving(mtmp->data) || !canspotmon(mtmp))
? "destroyed" : "killed");
/* don't blame hero for unknown rolling boulder trap */
if (!flags.mon_moving &&
(otmp->otyp != BOULDER || range >= 0 || !otmp->otrapped))
xkilled(mtmp,0);
else mondied(mtmp);
}
if (can_blnd((struct monst*)0, mtmp,
(uchar)(otmp->otyp == BLINDING_VENOM ? AT_SPIT : AT_WEAP),
otmp)) {
if (vis && mtmp->mcansee)
pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
mtmp->mcansee = 0;
tmp = (int)mtmp->mblinded + rnd(25) + 20;
if (tmp > 127) tmp = 127;
mtmp->mblinded = tmp;
}
objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y);
if (!objgone && range == -1) { /* special case */
obj_extract_self(otmp); /* free it for motion again */
return 0;
}
return 1;
}
return 0;
}
void
m_throw(mon, x, y, dx, dy, range, obj)
register struct monst *mon;
register int x,y,dx,dy,range; /* direction and range */
register struct obj *obj;
{
register struct monst *mtmp;
struct obj *singleobj;
char sym = obj->oclass;
int hitu, blindinc = 0;
bhitpos.x = x;
bhitpos.y = y;
if (obj->quan == 1L) {
/*
* Remove object from minvent. This cannot be done later on;
* what if the player dies before then, leaving the monster
* with 0 daggers? (This caused the infamous 2^32-1 orcish
* dagger bug).
*
* VENOM is not in minvent - it should already be OBJ_FREE.
* The extract below does nothing.
*/
/* not possibly_unwield, which checks the object's */
/* location, not its existence */
if (MON_WEP(mon) == obj) {
setmnotwielded(mon,obj);
MON_NOWEP(mon);
}
obj_extract_self(obj);
singleobj = obj;
obj = (struct obj *) 0;
} else {
singleobj = splitobj(obj, 1L);
obj_extract_self(singleobj);
}
singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */
if (singleobj->cursed && (dx || dy) && !rn2(7)) {
if(canseemon(mon) && flags.verbose) {
if(is_ammo(singleobj))
pline("%s misfires!", Monnam(mon));
else
pline("%s as %s throws it!",
Tobjnam(singleobj, "slip"), mon_nam(mon));
}
dx = rn2(3)-1;
dy = rn2(3)-1;
/* check validity of new direction */
if (!dx && !dy) {
(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
return;
}
}
/* pre-check for doors, walls and boundaries.
Also need to pre-check for bars regardless of direction;
the random chance for small objects hitting bars is
skipped when reaching them at point blank range */
if (!isok(bhitpos.x+dx,bhitpos.y+dy)
|| IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ)
|| closed_door(bhitpos.x+dx, bhitpos.y+dy)
|| (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS &&
hits_bars(&singleobj, bhitpos.x, bhitpos.y, 0, 0))) {
(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
return;
}
/* Note: drop_throw may destroy singleobj. Since obj must be destroyed
* early to avoid the dagger bug, anyone who modifies this code should
* be careful not to use either one after it's been freed.
*/
if (sym) tmp_at(DISP_FLASH, obj_to_glyph(singleobj));
while(range-- > 0) { /* Actually the loop is always exited by break */
bhitpos.x += dx;
bhitpos.y += dy;
if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
if (ohitmon(mtmp, singleobj, range, TRUE))
break;
} else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
if (multi) nomul(0);
if (singleobj->oclass == GEM_CLASS &&
singleobj->otyp <= LAST_GEM+9 /* 9 glass colors */
&& is_unicorn(youmonst.data)) {
if (singleobj->otyp > LAST_GEM) {
You("catch the %s.", xname(singleobj));
You("are not interested in %s junk.",
s_suffix(mon_nam(mon)));
makeknown(singleobj->otyp);
dropy(singleobj);
} else {
You("accept %s gift in the spirit in which it was intended.",
s_suffix(mon_nam(mon)));
(void)hold_another_object(singleobj,
"You catch, but drop, %s.", xname(singleobj),
"You catch:");
}
break;
}
if (singleobj->oclass == POTION_CLASS) {
if (!Blind) singleobj->dknown = 1;
potionhit(&youmonst, singleobj, FALSE);
break;
}
switch(singleobj->otyp) {
int dam, hitv;
case EGG:
if (!touch_petrifies(&mons[singleobj->corpsenm])) {
impossible("monster throwing egg type %d",
singleobj->corpsenm);
hitu = 0;
break;
}
/* fall through */
case CREAM_PIE:
case BLINDING_VENOM:
hitu = thitu(8, 0, singleobj, (char *)0);
break;
default:
dam = dmgval(singleobj, &youmonst);
hitv = 3 - distmin(u.ux,u.uy, mon->mx,mon->my);
if (hitv < -4) hitv = -4;
if (is_elf(mon->data) &&
objects[singleobj->otyp].oc_skill == P_BOW) {
hitv++;
if (MON_WEP(mon) &&
MON_WEP(mon)->otyp == ELVEN_BOW)
hitv++;
if(singleobj->otyp == ELVEN_ARROW) dam++;
}
if (bigmonst(youmonst.data)) hitv++;
hitv += 8 + singleobj->spe;
if (dam < 1) dam = 1;
hitu = thitu(hitv, dam, singleobj, (char *)0);
}
if (hitu && singleobj->opoisoned &&
is_poisonable(singleobj)) {
char onmbuf[BUFSZ], knmbuf[BUFSZ];
Strcpy(onmbuf, xname(singleobj));
Strcpy(knmbuf, killer_xname(singleobj));
poisoned(onmbuf, A_STR, knmbuf, -10);
}
if(hitu &&
can_blnd((struct monst*)0, &youmonst,
(uchar)(singleobj->otyp == BLINDING_VENOM ?
AT_SPIT : AT_WEAP), singleobj)) {
blindinc = rnd(25);
if(singleobj->otyp == CREAM_PIE) {
if(!Blind) pline("Yecch! You've been creamed.");
else pline("There's %s sticky all over your %s.",
something,
body_part(FACE));
} else if(singleobj->otyp == BLINDING_VENOM) {
int num_eyes = eyecount(youmonst.data);
/* venom in the eyes */
if(!Blind) pline_The("venom blinds you.");
else Your("%s sting%s.",
(num_eyes == 1) ? body_part(EYE) :
makeplural(body_part(EYE)),
(num_eyes == 1) ? "s" : "");
}
}
if (hitu && singleobj->otyp == EGG) {
if (!Stone_resistance
&& !(poly_when_stoned(youmonst.data) &&
polymon(PM_STONE_GOLEM))) {
Stoned = 5;
killer = (char *) 0;
}
}
stop_occupation();
if (hitu || !range) {
(void) drop_throw(singleobj, hitu, u.ux, u.uy);
break;
}
} else if (!range /* reached end of path */
/* missile hits edge of screen */
|| !isok(bhitpos.x+dx,bhitpos.y+dy)
/* missile hits the wall */
|| IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ)
/* missile hit closed door */
|| closed_door(bhitpos.x+dx, bhitpos.y+dy)
/* missile might hit iron bars */
|| (levl[bhitpos.x+dx][bhitpos.y+dy].typ == IRONBARS &&
hits_bars(&singleobj, bhitpos.x, bhitpos.y, !rn2(5), 0))
#ifdef SINKS
/* Thrown objects "sink" */
|| IS_SINK(levl[bhitpos.x][bhitpos.y].typ)
#endif
) {
if (singleobj) /* hits_bars might have destroyed it */
(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
break;
}
tmp_at(bhitpos.x, bhitpos.y);
delay_output();
}
tmp_at(bhitpos.x, bhitpos.y);
delay_output();
tmp_at(DISP_END, 0);
if (blindinc) {
u.ucreamed += blindinc;
make_blinded(Blinded + (long)blindinc, FALSE);
if (!Blind) Your(vision_clears);
}
}
#endif /* OVL1 */
#ifdef OVLB
/* Remove an item from the monster's inventory and destroy it. */
void
m_useup(mon, obj)
struct monst *mon;
struct obj *obj;
{
if (obj->quan > 1L) {
obj->quan--;
obj->owt = weight(obj);
} else {
obj_extract_self(obj);
possibly_unwield(mon, FALSE);
if (obj->owornmask) {
mon->misc_worn_check &= ~obj->owornmask;
update_mon_intrinsics(mon, obj, FALSE, FALSE);
}
obfree(obj, (struct obj*) 0);
}
}
#endif /* OVLB */
#ifdef OVL1
/* monster attempts ranged weapon attack against player */
void
thrwmu(mtmp)
struct monst *mtmp;
{
struct obj *otmp, *mwep;
xchar x, y;
schar skill;
int multishot;
const char *onm;
/* Rearranged beginning so monsters can use polearms not in a line */
if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
mtmp->weapon_check = NEED_RANGED_WEAPON;
/* mon_wield_item resets weapon_check as appropriate */
if(mon_wield_item(mtmp) != 0) return;
}
/* Pick a weapon */
otmp = select_rwep(mtmp);
if (!otmp) return;
if (is_pole(otmp)) {
int dam, hitv;
if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM ||
!couldsee(mtmp->mx, mtmp->my))
return; /* Out of range, or intervening wall */
if (canseemon(mtmp)) {
onm = xname(otmp);
pline("%s thrusts %s.", Monnam(mtmp),
obj_is_pname(otmp) ? the(onm) : an(onm));
}
dam = dmgval(otmp, &youmonst);
hitv = 3 - distmin(u.ux,u.uy, mtmp->mx,mtmp->my);
if (hitv < -4) hitv = -4;
if (bigmonst(youmonst.data)) hitv++;
hitv += 8 + otmp->spe;
if (dam < 1) dam = 1;
(void) thitu(hitv, dam, otmp, (char *)0);
stop_occupation();
return;
}
x = mtmp->mx;
y = mtmp->my;
/* If you are coming toward the monster, the monster
* should try to soften you up with missiles. If you are
* going away, you are probably hurt or running. Give
* chase, but if you are getting too far away, throw.
*/
if (!lined_up(mtmp) ||
(URETREATING(x,y) &&
rn2(BOLT_LIM - distmin(x,y,mtmp->mux,mtmp->muy))))
return;
skill = objects[otmp->otyp].oc_skill;
mwep = MON_WEP(mtmp); /* wielded weapon */
/* Multishot calculations */
multishot = 1;
if ((ammo_and_launcher(otmp, mwep) || skill == P_DAGGER ||
skill == -P_DART || skill == -P_SHURIKEN) && !mtmp->mconf) {
/* Assumes lords are skilled, princes are expert */
if (is_prince(mtmp->data)) multishot += 2;
else if (is_lord(mtmp->data)) multishot++;
switch (monsndx(mtmp->data)) {
case PM_RANGER:
multishot++;
break;
case PM_ROGUE:
if (skill == P_DAGGER) multishot++;
break;
case PM_NINJA:
case PM_SAMURAI:
if (otmp->otyp == YA && mwep &&
mwep->otyp == YUMI) multishot++;
break;
default:
break;
}
/* racial bonus */
if ((is_elf(mtmp->data) &&
otmp->otyp == ELVEN_ARROW &&
mwep && mwep->otyp == ELVEN_BOW) ||
(is_orc(mtmp->data) &&
otmp->otyp == ORCISH_ARROW &&
mwep && mwep->otyp == ORCISH_BOW))
multishot++;
if ((long)multishot > otmp->quan) multishot = (int)otmp->quan;
if (multishot < 1) multishot = 1;
else multishot = rnd(multishot);
}
if (canseemon(mtmp)) {
char onmbuf[BUFSZ];
if (multishot > 1) {
/* "N arrows"; multishot > 1 implies otmp->quan > 1, so
xname()'s result will already be pluralized */
Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
onm = onmbuf;
} else {
/* "an arrow" */
onm = singular(otmp, xname);
onm = obj_is_pname(otmp) ? the(onm) : an(onm);
}
m_shot.s = ammo_and_launcher(otmp,mwep) ? TRUE : FALSE;
pline("%s %s %s!", Monnam(mtmp),
m_shot.s ? "shoots" : "throws", onm);
m_shot.o = otmp->otyp;
} else {
m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
}
m_shot.n = multishot;
for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++)
m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
m_shot.n = m_shot.i = 0;
m_shot.o = STRANGE_OBJECT;
m_shot.s = FALSE;
nomul(0);
}
#endif /* OVL1 */
#ifdef OVLB
int
spitmu(mtmp, mattk) /* monster spits substance at you */
register struct monst *mtmp;
register struct attack *mattk;
{
register struct obj *otmp;
if(mtmp->mcan) {
if(flags.soundok)
pline("A dry rattle comes from %s throat.",
s_suffix(mon_nam(mtmp)));
return 0;
}
if(lined_up(mtmp)) {
switch (mattk->adtyp) {
case AD_BLND:
case AD_DRST:
otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
break;
default:
impossible("bad attack type in spitmu");
/* fall through */
case AD_ACID:
otmp = mksobj(ACID_VENOM, TRUE, FALSE);
break;
}
if(!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy))) {
if (canseemon(mtmp))
pline("%s spits venom!", Monnam(mtmp));
m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp);
nomul(0);
return 0;
}
}
return 0;
}
#endif /* OVLB */
#ifdef OVL1
int
breamu(mtmp, mattk) /* monster breathes at you (ranged) */
register struct monst *mtmp;
register struct attack *mattk;
{
/* if new breath types are added, change AD_ACID to max type */
int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
if(lined_up(mtmp)) {
if(mtmp->mcan) {
if(flags.soundok) {
if(canseemon(mtmp))
pline("%s coughs.", Monnam(mtmp));
else
You_hear("a cough.");
}
return(0);
}
if(!mtmp->mspec_used && rn2(3)) {
if((typ >= AD_MAGM) && (typ <= AD_ACID)) {
if(canseemon(mtmp))
pline("%s breathes %s!", Monnam(mtmp),
breathwep[typ-1]);
buzz((int) (-20 - (typ-1)), (int)mattk->damn,
mtmp->mx, mtmp->my, sgn(tbx), sgn(tby));
nomul(0);
/* breath runs out sometimes. Also, give monster some
* cunning; don't breath if the player fell asleep.
*/
if(!rn2(3))
mtmp->mspec_used = 10+rn2(20);
if(typ == AD_SLEE && !Sleep_resistance)
mtmp->mspec_used += rnd(20);
} else impossible("Breath weapon %d used", typ-1);
}
}
return(1);
}
boolean
linedup(ax, ay, bx, by)
register xchar ax, ay, bx, by;
{
tbx = ax - bx; /* These two values are set for use */
tby = ay - by; /* after successful return. */
/* sometimes displacement makes a monster think that you're at its
own location; prevent it from throwing and zapping in that case */
if (!tbx && !tby) return FALSE;
if((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */
&& distmin(tbx, tby, 0, 0) < BOLT_LIM) {
if(ax == u.ux && ay == u.uy) return((boolean)(couldsee(bx,by)));
else if(clear_path(ax,ay,bx,by)) return TRUE;
}
return FALSE;
}
boolean
lined_up(mtmp) /* is mtmp in position to use ranged attack? */
register struct monst *mtmp;
{
return(linedup(mtmp->mux,mtmp->muy,mtmp->mx,mtmp->my));
}
#endif /* OVL1 */
#ifdef OVL0
/* Check if a monster is carrying a particular item.
*/
struct obj *
m_carrying(mtmp, type)
struct monst *mtmp;
int type;
{
register struct obj *otmp;
for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
if(otmp->otyp == type)
return(otmp);
return((struct obj *) 0);
}
/* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
boolean
hits_bars(obj_p, x, y, always_hit, whodidit)
struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */
int x, y;
int always_hit; /* caller can force a hit for items which would fit through */
int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */
{
struct obj *otmp = *obj_p;
int obj_type = otmp->otyp;
boolean hits = always_hit;
if (!hits)
switch (otmp->oclass) {
case WEAPON_CLASS:
{
int oskill = objects[obj_type].oc_skill;
hits = (oskill != -P_BOW && oskill != -P_CROSSBOW &&
oskill != -P_DART && oskill != -P_SHURIKEN &&
oskill != P_SPEAR && oskill != P_JAVELIN &&
oskill != P_KNIFE); /* but not dagger */
break;
}
case ARMOR_CLASS:
hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
break;
case TOOL_CLASS:
hits = (obj_type != SKELETON_KEY &&
obj_type != LOCK_PICK &&
#ifdef TOURIST
obj_type != CREDIT_CARD &&
#endif
obj_type != TALLOW_CANDLE &&
obj_type != WAX_CANDLE &&
obj_type != LENSES &&
obj_type != TIN_WHISTLE &&
obj_type != MAGIC_WHISTLE);
break;
case ROCK_CLASS: /* includes boulder */
if (obj_type != STATUE ||
mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE;
break;
case FOOD_CLASS:
if (obj_type == CORPSE &&
mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE;
else
hits = (obj_type == MEAT_STICK ||
obj_type == HUGE_CHUNK_OF_MEAT);
break;
case SPBOOK_CLASS:
case WAND_CLASS:
case BALL_CLASS:
case CHAIN_CLASS:
hits = TRUE;
break;
default:
break;
}
if (hits && whodidit != -1) {
if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y))
*obj_p = otmp = 0; /* object is now gone */
/* breakage makes its own noises */
else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
pline("Whang!");
else if (otmp->oclass == COIN_CLASS ||
objects[obj_type].oc_material == GOLD ||
objects[obj_type].oc_material == SILVER)
pline("Clink!");
else
pline("Clonk!");
}
return hits;
}
#endif /* OVL0 */
/*mthrowu.c*/
Jump to Line
Something went wrong with that request. Please try again.