fix #K3455 - rocks vs xorns
Implement the suggestion that falling rock traps and rolling boulder traps be harmless to xorns. I've extended that to all missiles made of stone (rocks, gems, boulders, a handful of other things that will only matter if poly'd hero throws in '<' direction or is hit by stuff scattered by an explosion). I excluded ghosts because they would become even harder to kill and the missile handling would need extra checks to test for blessed objs.
This commit is contained in:
@@ -220,6 +220,11 @@
|
|||||||
#define touch_petrifies(ptr) \
|
#define touch_petrifies(ptr) \
|
||||||
((ptr) == &mons[PM_COCKATRICE] || (ptr) == &mons[PM_CHICKATRICE])
|
((ptr) == &mons[PM_COCKATRICE] || (ptr) == &mons[PM_CHICKATRICE])
|
||||||
|
|
||||||
|
/* missiles made of rocks don't harm these: xorns and earth elementals
|
||||||
|
(but not ghosts and shades because that would impact all missile use
|
||||||
|
and also require an exception for blessed rocks/gems/boulders) */
|
||||||
|
#define passes_rocks(ptr) (passes_walls(ptr) && !unsolid(ptr))
|
||||||
|
|
||||||
#define is_mind_flayer(ptr) \
|
#define is_mind_flayer(ptr) \
|
||||||
((ptr) == &mons[PM_MIND_FLAYER] || (ptr) == &mons[PM_MASTER_MIND_FLAYER])
|
((ptr) == &mons[PM_MIND_FLAYER] || (ptr) == &mons[PM_MASTER_MIND_FLAYER])
|
||||||
|
|
||||||
|
|||||||
@@ -226,6 +226,12 @@ struct obj {
|
|||||||
#define uslinging() (uwep && objects[uwep->otyp].oc_skill == P_SLING)
|
#define uslinging() (uwep && objects[uwep->otyp].oc_skill == P_SLING)
|
||||||
/* 'is_quest_artifact()' only applies to the current role's artifact */
|
/* 'is_quest_artifact()' only applies to the current role's artifact */
|
||||||
#define any_quest_artifact(o) ((o)->oartifact >= ART_ORB_OF_DETECTION)
|
#define any_quest_artifact(o) ((o)->oartifact >= ART_ORB_OF_DETECTION)
|
||||||
|
/* 'missile' aspect is up to the caller and does not imply is_missile();
|
||||||
|
rings might be launched as missiles when being scattered by an explosion */
|
||||||
|
#define stone_missile(o) \
|
||||||
|
((o) && (objects[(o)->otyp].oc_material == GEMSTONE \
|
||||||
|
|| (objects[(o)->otyp].oc_material == MINERAL)) \
|
||||||
|
&& (o)->oclass != RING_CLASS)
|
||||||
|
|
||||||
/* Armor */
|
/* Armor */
|
||||||
#define is_shield(otmp) \
|
#define is_shield(otmp) \
|
||||||
|
|||||||
@@ -1728,6 +1728,9 @@ x_monnam(
|
|||||||
falseCap = (*pm_name != lowc(*pm_name));
|
falseCap = (*pm_name != lowc(*pm_name));
|
||||||
char *bp;
|
char *bp;
|
||||||
|
|
||||||
|
if (mtmp == &g.youmonst)
|
||||||
|
return strcpy(buf, "you"); /* ignore article, "invisible", &c */
|
||||||
|
|
||||||
if (g.program_state.gameover)
|
if (g.program_state.gameover)
|
||||||
suppress |= SUPPRESS_HALLUCINATION;
|
suppress |= SUPPRESS_HALLUCINATION;
|
||||||
if (article == ARTICLE_YOUR && !mtmp->mtame)
|
if (article == ARTICLE_YOUR && !mtmp->mtame)
|
||||||
|
|||||||
+30
-12
@@ -535,9 +535,9 @@ endmultishot(boolean verbose)
|
|||||||
/* Object hits floor at hero's feet.
|
/* Object hits floor at hero's feet.
|
||||||
Called from drop(), throwit(), hold_another_object(), litter(). */
|
Called from drop(), throwit(), hold_another_object(), litter(). */
|
||||||
void
|
void
|
||||||
hitfloor(struct obj *obj,
|
hitfloor(
|
||||||
boolean verbosely) /* usually True; False if caller has given
|
struct obj *obj,
|
||||||
drop message */
|
boolean verbosely) /* usually True; False if caller has given drop mesg */
|
||||||
{
|
{
|
||||||
if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater || u.uswallow) {
|
if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater || u.uswallow) {
|
||||||
dropy(obj);
|
dropy(obj);
|
||||||
@@ -1056,7 +1056,8 @@ check_shop_obj(struct obj *obj, xchar x, xchar y, boolean broken)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Will 'obj' cause damage if it falls on hero's head when thrown upward?
|
/* Will 'obj' cause damage if it falls on hero's head when thrown upward?
|
||||||
Not used to handle things which break when they hit. */
|
Not used to handle things which break when they hit.
|
||||||
|
Stone missile hitting hero w/ Passes_walls attribute handled separately. */
|
||||||
static boolean
|
static boolean
|
||||||
harmless_missile(struct obj *obj)
|
harmless_missile(struct obj *obj)
|
||||||
{
|
{
|
||||||
@@ -1167,13 +1168,16 @@ toss_up(struct obj *obj, boolean hitsroof)
|
|||||||
hitfloor(obj, FALSE);
|
hitfloor(obj, FALSE);
|
||||||
g.thrownobj = 0;
|
g.thrownobj = 0;
|
||||||
} else { /* neither potion nor other breaking object */
|
} else { /* neither potion nor other breaking object */
|
||||||
boolean is_silver = (objects[otyp].oc_material == SILVER),
|
int material = objects[otyp].oc_material;
|
||||||
|
boolean is_silver = (material == SILVER),
|
||||||
less_damage = (uarmh && is_metallic(uarmh)
|
less_damage = (uarmh && is_metallic(uarmh)
|
||||||
&& (!is_silver || !Hate_silver)),
|
&& (!is_silver || !Hate_silver)),
|
||||||
|
harmless = (stone_missile(obj)
|
||||||
|
&& passes_rocks(g.youmonst.data)),
|
||||||
artimsg = FALSE;
|
artimsg = FALSE;
|
||||||
int dmg = dmgval(obj, &g.youmonst);
|
int dmg = dmgval(obj, &g.youmonst);
|
||||||
|
|
||||||
if (obj->oartifact)
|
if (obj->oartifact && !harmless)
|
||||||
/* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
|
/* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
|
||||||
artimsg = artifact_hit((struct monst *) 0, &g.youmonst, obj, &dmg,
|
artimsg = artifact_hit((struct monst *) 0, &g.youmonst, obj, &dmg,
|
||||||
rn1(18, 2));
|
rn1(18, 2));
|
||||||
@@ -1205,15 +1209,24 @@ toss_up(struct obj *obj, boolean hitsroof)
|
|||||||
dmg = Maybe_Half_Phys(dmg);
|
dmg = Maybe_Half_Phys(dmg);
|
||||||
|
|
||||||
if (uarmh) {
|
if (uarmh) {
|
||||||
if (less_damage && dmg < (Upolyd ? u.mh : u.uhp)) {
|
/* note: 'harmless' and 'petrifier' are mutually exclusive */
|
||||||
if (!artimsg)
|
if ((less_damage && dmg < (Upolyd ? u.mh : u.uhp)) || harmless) {
|
||||||
pline("Fortunately, you are wearing a hard helmet.");
|
if (!artimsg) {
|
||||||
|
if (!harmless) /* !harmless => less_damage here */
|
||||||
|
pline("Fortunately, you are wearing a hard helmet.");
|
||||||
|
else
|
||||||
|
pline("Unfortunately, you are wearing %s.",
|
||||||
|
an(helm_simple_name(uarmh))); /* helm or hat */
|
||||||
|
}
|
||||||
|
|
||||||
/* helmet definitely protects you when it blocks petrification */
|
/* helmet definitely protects you when it blocks petrification */
|
||||||
} else if (!petrifier) {
|
} else if (!petrifier) {
|
||||||
if (flags.verbose)
|
if (flags.verbose)
|
||||||
Your("%s does not protect you.", helm_simple_name(uarmh));
|
Your("%s does not protect you.", helm_simple_name(uarmh));
|
||||||
}
|
}
|
||||||
|
/* stone missile against hero in xorn form would have been
|
||||||
|
harmless, but hitting a worn helmet negates that */
|
||||||
|
harmless = FALSE;
|
||||||
} else if (petrifier && !Stone_resistance
|
} else if (petrifier && !Stone_resistance
|
||||||
&& !(poly_when_stoned(g.youmonst.data)
|
&& !(poly_when_stoned(g.youmonst.data)
|
||||||
&& polymon(PM_STONE_GOLEM))) {
|
&& polymon(PM_STONE_GOLEM))) {
|
||||||
@@ -1229,9 +1242,13 @@ toss_up(struct obj *obj, boolean hitsroof)
|
|||||||
}
|
}
|
||||||
if (is_silver && Hate_silver)
|
if (is_silver && Hate_silver)
|
||||||
pline_The("silver sears you!");
|
pline_The("silver sears you!");
|
||||||
|
if (harmless)
|
||||||
|
hit(thesimpleoname(obj), &g.youmonst, " but doesn't hurt.");
|
||||||
|
|
||||||
hitfloor(obj, TRUE);
|
hitfloor(obj, TRUE);
|
||||||
g.thrownobj = 0;
|
g.thrownobj = 0;
|
||||||
losehp(dmg, "falling object", KILLED_BY_AN);
|
if (!harmless)
|
||||||
|
losehp(dmg, "falling object", KILLED_BY_AN);
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -1692,8 +1709,9 @@ tmiss(struct obj *obj, struct monst *mon, boolean maybe_wakeup)
|
|||||||
* Also used for kicked objects and for polearms/grapnel applied at range.
|
* Also used for kicked objects and for polearms/grapnel applied at range.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
thitmonst(register struct monst *mon,
|
thitmonst(
|
||||||
register struct obj *obj) /* g.thrownobj or g.kickedobj or uwep */
|
struct monst *mon,
|
||||||
|
struct obj *obj) /* g.thrownobj or g.kickedobj or uwep */
|
||||||
{
|
{
|
||||||
register int tmp; /* Base chance to hit */
|
register int tmp; /* Base chance to hit */
|
||||||
register int disttmp; /* distance modifier */
|
register int disttmp; /* distance modifier */
|
||||||
|
|||||||
+30
-11
@@ -37,17 +37,18 @@ m_has_launcher_and_ammo(struct monst* mtmp)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hero is hit by something other than a monster */
|
/* hero is hit by something other than a monster (though it could be a
|
||||||
|
missile thrown or shot by a monster) */
|
||||||
int
|
int
|
||||||
thitu(
|
thitu(
|
||||||
int tlev,
|
int tlev, /* pseudo-level used when deciding whether to hit hero's AC */
|
||||||
int dam,
|
int dam,
|
||||||
struct obj **objp,
|
struct obj **objp,
|
||||||
const char *name) /* if null, then format `*objp' */
|
const char *name) /* if null, then format `*objp' */
|
||||||
{
|
{
|
||||||
struct obj *obj = objp ? *objp : 0;
|
struct obj *obj = objp ? *objp : 0;
|
||||||
const char *onm, *knm;
|
const char *onm, *knm;
|
||||||
boolean is_acid;
|
boolean is_acid, named = (name != 0);
|
||||||
int kprefix = KILLED_BY_AN, dieroll;
|
int kprefix = KILLED_BY_AN, dieroll;
|
||||||
char onmbuf[BUFSZ], knmbuf[BUFSZ];
|
char onmbuf[BUFSZ], knmbuf[BUFSZ];
|
||||||
|
|
||||||
@@ -90,6 +91,13 @@ thitu(
|
|||||||
if (is_acid && Acid_resistance) {
|
if (is_acid && Acid_resistance) {
|
||||||
pline("It doesn't seem to hurt you.");
|
pline("It doesn't seem to hurt you.");
|
||||||
monstseesu(M_SEEN_ACID);
|
monstseesu(M_SEEN_ACID);
|
||||||
|
} else if (stone_missile(obj) && passes_rocks(g.youmonst.data)) {
|
||||||
|
/* use 'named' as an approximation for "hitting from above";
|
||||||
|
we avoid "passes through you" for horizontal flight path
|
||||||
|
because missile stops and that wording would suggest that
|
||||||
|
it should keep going */
|
||||||
|
pline("It %s you.",
|
||||||
|
named ? "passes harmlessly through" : "doesn't harm");
|
||||||
} else if (obj && obj->oclass == POTION_CLASS) {
|
} else if (obj && obj->oclass == POTION_CLASS) {
|
||||||
/* an explosion which scatters objects might hit hero with one
|
/* an explosion which scatters objects might hit hero with one
|
||||||
(potions deliberately thrown at hero are handled by m_throw) */
|
(potions deliberately thrown at hero are handled by m_throw) */
|
||||||
@@ -280,8 +288,8 @@ ohitmon(
|
|||||||
struct monst *mtmp, /* accidental target, located at <g.bhitpos.x,.y> */
|
struct monst *mtmp, /* accidental target, located at <g.bhitpos.x,.y> */
|
||||||
struct obj *otmp, /* missile; might be destroyed by drop_throw */
|
struct obj *otmp, /* missile; might be destroyed by drop_throw */
|
||||||
int range, /* how much farther will object travel if it misses;
|
int range, /* how much farther will object travel if it misses;
|
||||||
use -1 to signify to keep going even after hit,
|
* use -1 to signify to keep going even after hit,
|
||||||
unless it's gone (used for rolling_boulder_traps) */
|
* unless it's gone (used for rolling_boulder_traps) */
|
||||||
boolean verbose)/* give message(s) even when you can't see what happened */
|
boolean verbose)/* give message(s) even when you can't see what happened */
|
||||||
{
|
{
|
||||||
int damage, tmp;
|
int damage, tmp;
|
||||||
@@ -325,6 +333,9 @@ ohitmon(
|
|||||||
potionhit(mtmp, otmp, POTHIT_OTHER_THROW);
|
potionhit(mtmp, otmp, POTHIT_OTHER_THROW);
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
|
int material = objects[otmp->otyp].oc_material;
|
||||||
|
boolean harmless = (stone_missile(otmp) && passes_rocks(mtmp->data));
|
||||||
|
|
||||||
damage = dmgval(otmp, mtmp);
|
damage = dmgval(otmp, mtmp);
|
||||||
if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
|
if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
|
||||||
damage = 0;
|
damage = 0;
|
||||||
@@ -336,12 +347,20 @@ ohitmon(
|
|||||||
seemimic(mtmp);
|
seemimic(mtmp);
|
||||||
mtmp->msleeping = 0;
|
mtmp->msleeping = 0;
|
||||||
if (vis) {
|
if (vis) {
|
||||||
if (otmp->otyp == EGG)
|
if (otmp->otyp == EGG) {
|
||||||
pline("Splat! %s is hit with %s egg!", Monnam(mtmp),
|
pline("Splat! %s is hit with %s egg!", Monnam(mtmp),
|
||||||
otmp->known ? an(mons[otmp->corpsenm].pmnames[NEUTRAL])
|
otmp->known ? an(mons[otmp->corpsenm].pmnames[NEUTRAL])
|
||||||
: "an");
|
: "an");
|
||||||
else
|
} else {
|
||||||
hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
|
char how[BUFSZ];
|
||||||
|
|
||||||
|
if (!harmless)
|
||||||
|
Strcpy(how, exclam(damage)); /* "!" or "." */
|
||||||
|
else
|
||||||
|
Sprintf(how, " but passes harmlessly through %.9s.",
|
||||||
|
mhim(mtmp));
|
||||||
|
hit(distant_name(otmp, mshot_xname), mtmp, how);
|
||||||
|
}
|
||||||
} else if (verbose && !g.mtarget)
|
} else if (verbose && !g.mtarget)
|
||||||
pline("%s%s is hit%s", (otmp->otyp == EGG) ? "Splat! " : "",
|
pline("%s%s is hit%s", (otmp->otyp == EGG) ? "Splat! " : "",
|
||||||
Monnam(mtmp), exclam(damage));
|
Monnam(mtmp), exclam(damage));
|
||||||
@@ -361,8 +380,7 @@ ohitmon(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (objects[otmp->otyp].oc_material == SILVER
|
if (material == SILVER && mon_hates_silver(mtmp)) {
|
||||||
&& mon_hates_silver(mtmp)) {
|
|
||||||
boolean flesh = (!noncorporeal(mtmp->data)
|
boolean flesh = (!noncorporeal(mtmp->data)
|
||||||
&& !amorphous(mtmp->data));
|
&& !amorphous(mtmp->data));
|
||||||
|
|
||||||
@@ -395,7 +413,8 @@ ohitmon(
|
|||||||
damage = 0;
|
damage = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DEADMONSTER(mtmp)) { /* might already be dead (if petrified) */
|
/* might already be dead (if petrified) */
|
||||||
|
if (!harmless && !DEADMONSTER(mtmp)) {
|
||||||
mtmp->mhp -= damage;
|
mtmp->mhp -= damage;
|
||||||
if (DEADMONSTER(mtmp)) {
|
if (DEADMONSTER(mtmp)) {
|
||||||
if (vis || (verbose && !g.mtarget))
|
if (vis || (verbose && !g.mtarget))
|
||||||
|
|||||||
+41
-27
@@ -9,8 +9,7 @@ extern const char *const destroy_strings[][3]; /* from zap.c */
|
|||||||
|
|
||||||
static boolean keep_saddle_with_steedcorpse(unsigned, struct obj *,
|
static boolean keep_saddle_with_steedcorpse(unsigned, struct obj *,
|
||||||
struct obj *);
|
struct obj *);
|
||||||
static boolean mu_maybe_destroy_web(struct monst *, boolean,
|
static boolean mu_maybe_destroy_web(struct monst *, boolean, struct trap *);
|
||||||
struct trap *);
|
|
||||||
static struct obj *t_missile(int, struct trap *);
|
static struct obj *t_missile(int, struct trap *);
|
||||||
static int trapeffect_arrow_trap(struct monst *, struct trap *, unsigned);
|
static int trapeffect_arrow_trap(struct monst *, struct trap *, unsigned);
|
||||||
static int trapeffect_dart_trap(struct monst *, struct trap *, unsigned);
|
static int trapeffect_dart_trap(struct monst *, struct trap *, unsigned);
|
||||||
@@ -1060,6 +1059,7 @@ trapeffect_rocktrap(
|
|||||||
unsigned trflags UNUSED)
|
unsigned trflags UNUSED)
|
||||||
{
|
{
|
||||||
struct obj *otmp;
|
struct obj *otmp;
|
||||||
|
boolean harmless = FALSE;
|
||||||
|
|
||||||
if (mtmp == &g.youmonst) {
|
if (mtmp == &g.youmonst) {
|
||||||
if (trap->once && trap->tseen && !rn2(15)) {
|
if (trap->once && trap->tseen && !rn2(15)) {
|
||||||
@@ -1078,20 +1078,31 @@ trapeffect_rocktrap(
|
|||||||
pline("A trap door in %s opens and %s falls on your %s!",
|
pline("A trap door in %s opens and %s falls on your %s!",
|
||||||
the(ceiling(u.ux, u.uy)), an(xname(otmp)), body_part(HEAD));
|
the(ceiling(u.ux, u.uy)), an(xname(otmp)), body_part(HEAD));
|
||||||
if (uarmh) {
|
if (uarmh) {
|
||||||
if (is_metallic(uarmh)) {
|
/* normally passes_rocks() would protect againt a falling
|
||||||
|
rock, but not when wearing a helmet */
|
||||||
|
if (passes_rocks(g.youmonst.data)) {
|
||||||
|
pline("Unfortunately, you are wearing %s.",
|
||||||
|
an(helm_simple_name(uarmh))); /* helm or hat */
|
||||||
|
dmg = 2;
|
||||||
|
} else if (is_metallic(uarmh)) {
|
||||||
pline("Fortunately, you are wearing a hard helmet.");
|
pline("Fortunately, you are wearing a hard helmet.");
|
||||||
dmg = 2;
|
dmg = 2;
|
||||||
} else if (flags.verbose) {
|
} else if (flags.verbose) {
|
||||||
pline("%s does not protect you.", Yname2(uarmh));
|
pline("%s does not protect you.", Yname2(uarmh));
|
||||||
}
|
}
|
||||||
|
} else if (passes_rocks(g.youmonst.data)) {
|
||||||
|
pline("It passes harmlessly through you.");
|
||||||
|
harmless = TRUE;
|
||||||
}
|
}
|
||||||
if (!Blind)
|
if (!Blind)
|
||||||
otmp->dknown = 1;
|
otmp->dknown = 1;
|
||||||
stackobj(otmp);
|
stackobj(otmp);
|
||||||
newsym(u.ux, u.uy); /* map the rock */
|
newsym(u.ux, u.uy); /* map the rock */
|
||||||
|
|
||||||
losehp(Maybe_Half_Phys(dmg), "falling rock", KILLED_BY_AN);
|
if (!harmless) {
|
||||||
exercise(A_STR, FALSE);
|
losehp(Maybe_Half_Phys(dmg), "falling rock", KILLED_BY_AN);
|
||||||
|
exercise(A_STR, FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed);
|
boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed);
|
||||||
@@ -2655,15 +2666,13 @@ force_launch_placement(void)
|
|||||||
int
|
int
|
||||||
launch_obj(
|
launch_obj(
|
||||||
short otyp,
|
short otyp,
|
||||||
register int x1,
|
int x1, int y1,
|
||||||
register int y1,
|
int x2, int y2,
|
||||||
register int x2,
|
|
||||||
register int y2,
|
|
||||||
int style)
|
int style)
|
||||||
{
|
{
|
||||||
register struct monst *mtmp;
|
struct monst *mtmp;
|
||||||
register struct obj *otmp, *otmp2;
|
struct obj *otmp, *otmp2;
|
||||||
register int dx, dy;
|
int dx, dy;
|
||||||
struct obj *singleobj;
|
struct obj *singleobj;
|
||||||
boolean used_up = FALSE;
|
boolean used_up = FALSE;
|
||||||
boolean otherside = FALSE;
|
boolean otherside = FALSE;
|
||||||
@@ -2733,8 +2742,8 @@ launch_obj(
|
|||||||
singleobj->otrapped = 1;
|
singleobj->otrapped = 1;
|
||||||
style &= ~LAUNCH_KNOWN;
|
style &= ~LAUNCH_KNOWN;
|
||||||
/*FALLTHRU*/
|
/*FALLTHRU*/
|
||||||
roll:
|
|
||||||
case ROLL:
|
case ROLL:
|
||||||
|
roll:
|
||||||
delaycnt = 2;
|
delaycnt = 2;
|
||||||
/*FALLTHRU*/
|
/*FALLTHRU*/
|
||||||
default:
|
default:
|
||||||
@@ -5637,14 +5646,13 @@ b_trapped(const char* item, int bodypart)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Monster is hit by trap. */
|
/* Monster is hit by trap. */
|
||||||
/* Note: doesn't work if both obj and d_override are null */
|
|
||||||
static boolean
|
static boolean
|
||||||
thitm(
|
thitm(
|
||||||
int tlev,
|
int tlev, /* missile's attack level */
|
||||||
struct monst *mon,
|
struct monst *mon, /* target */
|
||||||
struct obj *obj,
|
struct obj *obj, /* missile; might be Null */
|
||||||
int d_override,
|
int d_override, /* non-zero: force hit for this amount of damage */
|
||||||
boolean nocorpse)
|
boolean nocorpse) /* True: a trap is completely burning up the target */
|
||||||
{
|
{
|
||||||
int strike;
|
int strike;
|
||||||
boolean trapkilled = FALSE;
|
boolean trapkilled = FALSE;
|
||||||
@@ -5664,9 +5672,11 @@ thitm(
|
|||||||
pline("%s is almost hit by %s!", Monnam(mon), doname(obj));
|
pline("%s is almost hit by %s!", Monnam(mon), doname(obj));
|
||||||
} else {
|
} else {
|
||||||
int dam = 1;
|
int dam = 1;
|
||||||
|
boolean harmless = (stone_missile(obj) && passes_rocks(mon->data));
|
||||||
|
|
||||||
if (obj && cansee(mon->mx, mon->my))
|
if (obj && cansee(mon->mx, mon->my))
|
||||||
pline("%s is hit by %s!", Monnam(mon), doname(obj));
|
pline("%s is hit by %s%s", Monnam(mon), doname(obj),
|
||||||
|
harmless ? " but is not harmed." : "!");
|
||||||
if (d_override) {
|
if (d_override) {
|
||||||
dam = d_override;
|
dam = d_override;
|
||||||
} else if (obj) {
|
} else if (obj) {
|
||||||
@@ -5674,15 +5684,19 @@ thitm(
|
|||||||
if (dam < 1)
|
if (dam < 1)
|
||||||
dam = 1;
|
dam = 1;
|
||||||
}
|
}
|
||||||
mon->mhp -= dam;
|
if (!harmless) {
|
||||||
if (mon->mhp <= 0) {
|
mon->mhp -= dam;
|
||||||
int xx = mon->mx, yy = mon->my;
|
if (mon->mhp <= 0) {
|
||||||
|
int xx = mon->mx, yy = mon->my;
|
||||||
|
|
||||||
monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS);
|
monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS);
|
||||||
if (DEADMONSTER(mon)) {
|
if (DEADMONSTER(mon)) {
|
||||||
newsym(xx, yy);
|
newsym(xx, yy);
|
||||||
trapkilled = TRUE;
|
trapkilled = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
strike = 0; /* harmless; don't use up the missile */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (obj && (!strike || d_override)) {
|
if (obj && (!strike || d_override)) {
|
||||||
|
|||||||
+35
-27
@@ -295,11 +295,12 @@ mon_maybe_wakeup_on_hit(struct monst *mtmp)
|
|||||||
using attack type aatyp and/or weapon.
|
using attack type aatyp and/or weapon.
|
||||||
larger value == easier to hit */
|
larger value == easier to hit */
|
||||||
int
|
int
|
||||||
find_roll_to_hit(struct monst *mtmp,
|
find_roll_to_hit(
|
||||||
uchar aatyp, /* usually AT_WEAP or AT_KICK */
|
struct monst *mtmp,
|
||||||
struct obj *weapon, /* uwep or uswapwep or NULL */
|
uchar aatyp, /* usually AT_WEAP or AT_KICK */
|
||||||
int *attk_count,
|
struct obj *weapon, /* uwep or uswapwep or NULL */
|
||||||
int *role_roll_penalty)
|
int *attk_count,
|
||||||
|
int *role_roll_penalty)
|
||||||
{
|
{
|
||||||
int tmp, tmp2;
|
int tmp, tmp2;
|
||||||
|
|
||||||
@@ -574,10 +575,9 @@ known_hitum(
|
|||||||
/* hit the monster next to you and the monsters to the left and right of it;
|
/* hit the monster next to you and the monsters to the left and right of it;
|
||||||
return False if the primary target is killed, True otherwise */
|
return False if the primary target is killed, True otherwise */
|
||||||
static boolean
|
static boolean
|
||||||
hitum_cleave(struct monst *target, /* non-Null; forcefight at nothing doesn't
|
hitum_cleave(
|
||||||
cleave... */
|
struct monst *target, /* non-Null; forcefight at nothing doesn't cleave +*/
|
||||||
struct attack *uattk) /* ... but we don't enforce that here; Null
|
struct attack *uattk) /*+ but we don't enforce that here; Null works ok */
|
||||||
works ok */
|
|
||||||
{
|
{
|
||||||
/* swings will be delivered in alternate directions; with consecutive
|
/* swings will be delivered in alternate directions; with consecutive
|
||||||
attacks it will simulate normal swing and backswing; when swings
|
attacks it will simulate normal swing and backswing; when swings
|
||||||
@@ -723,12 +723,13 @@ hmon(struct monst *mon,
|
|||||||
|
|
||||||
DISABLE_WARNING_FORMAT_NONLITERAL
|
DISABLE_WARNING_FORMAT_NONLITERAL
|
||||||
|
|
||||||
/* guts of hmon() */
|
/* guts of hmon(); returns True if 'mon' survives */
|
||||||
static boolean
|
static boolean
|
||||||
hmon_hitmon(struct monst *mon,
|
hmon_hitmon(
|
||||||
struct obj *obj,
|
struct monst *mon,
|
||||||
int thrown, /* HMON_xxx (0 => hand-to-hand, other => ranged) */
|
struct obj *obj,
|
||||||
int dieroll)
|
int thrown, /* HMON_xxx (0 => hand-to-hand, other => ranged) */
|
||||||
|
int dieroll)
|
||||||
{
|
{
|
||||||
int tmp;
|
int tmp;
|
||||||
struct permonst *mdat = mon->data;
|
struct permonst *mdat = mon->data;
|
||||||
@@ -751,7 +752,7 @@ hmon_hitmon(struct monst *mon,
|
|||||||
/* not grapnels; applied implies uwep */
|
/* not grapnels; applied implies uwep */
|
||||||
|| (thrown == HMON_APPLIED && is_pole(uwep)));
|
|| (thrown == HMON_APPLIED && is_pole(uwep)));
|
||||||
int jousting = 0;
|
int jousting = 0;
|
||||||
long silverhit = 0L;
|
int material = obj ? objects[obj->otyp].oc_material : 0;
|
||||||
int wtype;
|
int wtype;
|
||||||
struct obj *monwep;
|
struct obj *monwep;
|
||||||
char saved_oname[BUFSZ];
|
char saved_oname[BUFSZ];
|
||||||
@@ -760,6 +761,8 @@ hmon_hitmon(struct monst *mon,
|
|||||||
|
|
||||||
wakeup(mon, TRUE);
|
wakeup(mon, TRUE);
|
||||||
if (!obj) { /* attack with bare hands */
|
if (!obj) { /* attack with bare hands */
|
||||||
|
long silverhit = 0L; /* armor mask */
|
||||||
|
|
||||||
if (mdat == &mons[PM_SHADE]) {
|
if (mdat == &mons[PM_SHADE]) {
|
||||||
tmp = 0;
|
tmp = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -781,10 +784,20 @@ hmon_hitmon(struct monst *mon,
|
|||||||
silvermsg = TRUE;
|
silvermsg = TRUE;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
/* stone missile does not hurt xorn or earth elemental, but doesn't
|
||||||
|
pass all the way through and continue on to some further target */
|
||||||
|
if ((thrown == HMON_THROWN || thrown == HMON_KICKED) /* not Applied */
|
||||||
|
&& stone_missile(obj) && passes_rocks(mdat)) {
|
||||||
|
hit(mshot_xname(obj), mon, " but does no harm.");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
/* remember obj's name since it might end up being destroyed and
|
||||||
|
we'll want to use it after that */
|
||||||
if (!(artifact_light(obj) && obj->lamplit))
|
if (!(artifact_light(obj) && obj->lamplit))
|
||||||
Strcpy(saved_oname, cxname(obj));
|
Strcpy(saved_oname, cxname(obj));
|
||||||
else
|
else
|
||||||
Strcpy(saved_oname, bare_artifactname(obj));
|
Strcpy(saved_oname, bare_artifactname(obj));
|
||||||
|
|
||||||
if (obj->oclass == WEAPON_CLASS || is_weptool(obj)
|
if (obj->oclass == WEAPON_CLASS || is_weptool(obj)
|
||||||
|| obj->oclass == GEM_CLASS) {
|
|| obj->oclass == GEM_CLASS) {
|
||||||
/* is it not a melee weapon? */
|
/* is it not a melee weapon? */
|
||||||
@@ -803,10 +816,8 @@ hmon_hitmon(struct monst *mon,
|
|||||||
tmp = 0;
|
tmp = 0;
|
||||||
else
|
else
|
||||||
tmp = rnd(2);
|
tmp = rnd(2);
|
||||||
if (objects[obj->otyp].oc_material == SILVER
|
if (material == SILVER && mon_hates_silver(mon)) {
|
||||||
&& mon_hates_silver(mon)) {
|
silvermsg = silverobj = TRUE;
|
||||||
silvermsg = TRUE;
|
|
||||||
silverobj = TRUE;
|
|
||||||
/* if it will already inflict dmg, make it worse */
|
/* if it will already inflict dmg, make it worse */
|
||||||
tmp += rnd((tmp) ? 20 : 10);
|
tmp += rnd((tmp) ? 20 : 10);
|
||||||
}
|
}
|
||||||
@@ -891,10 +902,8 @@ hmon_hitmon(struct monst *mon,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
hittxt = TRUE;
|
hittxt = TRUE;
|
||||||
}
|
}
|
||||||
if (objects[obj->otyp].oc_material == SILVER
|
if (material == SILVER && mon_hates_silver(mon)) {
|
||||||
&& mon_hates_silver(mon)) {
|
silvermsg = silverobj = TRUE;
|
||||||
silvermsg = TRUE;
|
|
||||||
silverobj = TRUE;
|
|
||||||
}
|
}
|
||||||
if (artifact_light(obj) && obj->lamplit
|
if (artifact_light(obj) && obj->lamplit
|
||||||
&& mon_hates_light(mon))
|
&& mon_hates_light(mon))
|
||||||
@@ -1168,8 +1177,7 @@ hmon_hitmon(struct monst *mon,
|
|||||||
}
|
}
|
||||||
/* things like silver wands can arrive here so we
|
/* things like silver wands can arrive here so we
|
||||||
need another silver check; blessed check too */
|
need another silver check; blessed check too */
|
||||||
if (objects[obj->otyp].oc_material == SILVER
|
if (material == SILVER && mon_hates_silver(mon)) {
|
||||||
&& mon_hates_silver(mon)) {
|
|
||||||
tmp += rnd(20);
|
tmp += rnd(20);
|
||||||
silvermsg = silverobj = TRUE;
|
silvermsg = silverobj = TRUE;
|
||||||
}
|
}
|
||||||
@@ -1336,9 +1344,9 @@ hmon_hitmon(struct monst *mon,
|
|||||||
/* iron weapon using melee or polearm hit [3.6.1: metal weapon too;
|
/* iron weapon using melee or polearm hit [3.6.1: metal weapon too;
|
||||||
also allow either or both weapons to cause split when twoweap] */
|
also allow either or both weapons to cause split when twoweap] */
|
||||||
&& obj && (obj == uwep || (u.twoweap && obj == uswapwep))
|
&& obj && (obj == uwep || (u.twoweap && obj == uswapwep))
|
||||||
&& ((objects[obj->otyp].oc_material == IRON
|
&& ((material == IRON
|
||||||
/* allow scalpel and tsurugi to split puddings */
|
/* allow scalpel and tsurugi to split puddings */
|
||||||
|| objects[obj->otyp].oc_material == METAL)
|
|| material == METAL)
|
||||||
/* but not bashing with darts, arrows or ya */
|
/* but not bashing with darts, arrows or ya */
|
||||||
&& !(is_ammo(obj) || is_missile(obj)))
|
&& !(is_ammo(obj) || is_missile(obj)))
|
||||||
&& hand_to_hand) {
|
&& hand_to_hand) {
|
||||||
|
|||||||
@@ -3309,11 +3309,16 @@ exclam(int force)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
hit(const char *str, struct monst *mtmp,
|
hit(const char *str, /* zap text or missile name */
|
||||||
const char *force) /* usually either "." or "!" */
|
struct monst *mtmp, /* target; for missile, might be hero */
|
||||||
|
const char *force) /* usually either "." or "!" via exclam() */
|
||||||
{
|
{
|
||||||
if ((!cansee(g.bhitpos.x, g.bhitpos.y) && !canspotmon(mtmp)
|
boolean verbosely = (mtmp == &g.youmonst
|
||||||
&& !engulfing_u(mtmp)) || !flags.verbose)
|
|| (flags.verbose
|
||||||
|
&& (cansee(g.bhitpos.x, g.bhitpos.y)
|
||||||
|
|| canspotmon(mtmp) || engulfing_u(mtmp))));
|
||||||
|
|
||||||
|
if (!verbosely)
|
||||||
pline("%s %s it.", The(str), vtense(str, "hit"));
|
pline("%s %s it.", The(str), vtense(str, "hit"));
|
||||||
else
|
else
|
||||||
pline("%s %s %s%s", The(str), vtense(str, "hit"),
|
pline("%s %s %s%s", The(str), vtense(str, "hit"),
|
||||||
|
|||||||
Reference in New Issue
Block a user