-/* NetHack 3.6 mhitu.c $NHDT-Date: 1513297347 2017/12/15 00:22:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.149 $ */
+/* NetHack 3.6 mhitu.c $NHDT-Date: 1575245065 2019/12/02 00:04:25 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.168 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
/* JNetHack Copyright */
/* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
-/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019 */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
/* JNetHack may be freely redistributed. See license for details. */
#include "hack.h"
STATIC_DCL boolean FDECL(u_slip_free, (struct monst *, struct attack *));
STATIC_DCL int FDECL(passiveum, (struct permonst *, struct monst *,
struct attack *));
-STATIC_DCL void FDECL(mayberem, (struct obj *, const char *));
+STATIC_DCL void FDECL(mayberem, (struct monst *, const char *,
+ struct obj *, const char *));
STATIC_DCL boolean FDECL(diseasemu, (struct permonst *));
STATIC_DCL int FDECL(hitmu, (struct monst *, struct attack *));
STATIC_DCL int FDECL(gulpmu, (struct monst *, struct attack *));
&& !mtmp->mcan && !mtmp->mspec_used) {
#if 0 /*JP:T*/
pline("%s %s you %s.", Monst_name,
- Blind ? "talks to" : "smiles at",
+ !Blind ? "smiles at" : !Deaf ? "talks to" : "touches",
(compat == 2) ? "engagingly" : "seductively");
#else
pline("%s\82Í\82 \82È\82½%s%s\81D", Monst_name,
(compat == 2) ? "\82ð\88ø\82«\82Â\82¯\82é\82æ\82¤\82É" : "\82É\8dD\88Ó\82ð\82æ\82¹\82é\82æ\82¤\82É",
- Blind ? "\98b\82µ\82©\82¯\82½" : "\94÷\8fÎ\82ñ\82¾");
+ !Blind ? "\94÷\8fÎ\82ñ\82¾" : !Deaf ? "\98b\82µ\82©\82¯\82½" : "\90G\82ê\82½");
#endif
} else {
switch (mattk->aatyp) {
*/
pline("%s\82Í\97F\8dD\93I\82È\82Ó\82è\82ð\82µ\82Ä\82¢\82é\81D",Monnam(mtmp));
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %smisses!", Monnam(mtmp),
(nearmiss && flags.verbose) ? "just " : "");
#else
*/
return (!mwep || !mwep->opoisoned) ? "\8dU\8c\82" : "\95\90\8aí";
} else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
return (mattk->aatyp == AT_TUCH) ? "contact"
: (mattk->aatyp == AT_GAZE) ? "gaze"
: (mattk->aatyp == AT_BITE) ? "bite" : "sting";
/* maybe it's attacking an image around the corner? */
compat = ((mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX)
- && could_seduce(mtmp, &youmonst, (struct attack *) 0));
+ ? could_seduce(mtmp, &youmonst, mattk) : 0);
Monst_name = Monnam(mtmp);
if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
pline("%s\82Ì\8dU\8c\82\82Í\82 \82È\82½\82Ì\98e\95 \82ð\82©\82·\82ß\82½\81D", Monst_name);
break;
case 2:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s strikes at %s!", Monst_name,
(levl[mtmp->mux][mtmp->muy].typ == WATER)
? "empty water"
}
} else if (Displaced) {
+ /* give 'displaced' message even if hero is Blind */
if (compat)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s smiles %s at your %sdisplaced image...", Monst_name,
(compat == 2) ? "engagingly" : "seductively",
Invis ? "invisible " : "");
(compat == 2) ? "\96£\97Í\93I\82É" : "\97U\98f\93I\82É");
#endif
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s strikes at your %sdisplaced image and misses you!",
- /* Note: if you're both invisible and displaced,
- * only monsters which see invisible will attack your
- * displaced image, since the displaced image is also
- * invisible.
- */
+ /* Note: if you're both invisible and displaced, only
+ * monsters which see invisible will attack your displaced
+ * image, since the displaced image is also invisible. */
Monst_name, Invis ? "invisible " : "");
#else
pline("%s\82Í\82 \82È\82½\82Ì%s\8c¶\89e\82ð\8dU\8c\82\82µ\81C\82Í\82¸\82µ\82½\81I",
struct attack *attk = &mptr->mattk[indx];
struct obj *weap = (magr == &youmonst) ? uwep : MON_WEP(magr);
+ /* honor SEDUCE=0 */
+ if (!SYSOPT_SEDUCE) {
+ extern const struct attack sa_no[NATTK];
+
+ /* if the first attack is for SSEX damage, all six attacks will be
+ substituted (expected succubus/incubus handling); if it isn't
+ but another one is, only that other one will be substituted */
+ if (mptr->mattk[0].adtyp == AD_SSEX) {
+ *alt_attk_buf = sa_no[indx];
+ attk = alt_attk_buf;
+ } else if (attk->adtyp == AD_SSEX) {
+ *alt_attk_buf = *attk;
+ attk = alt_attk_buf;
+ attk->adtyp = AD_DRLI;
+ }
+ }
+
/* prevent a monster with two consecutive disease or hunger attacks
from hitting with both of them on the same turn; if the first has
already hit, switch to a stun attack for the second */
if (!ranged)
nomul(0);
- if (mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data)))
+ if (DEADMONSTER(mtmp) || (Underwater && !is_swimmer(mtmp->data)))
return 0;
/* If swallowed, can only be affected by u.ustuck */
obj = which_armor(mtmp, WORN_HELMET);
if (obj && is_metallic(obj)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Your("blow glances off %s %s.", s_suffix(mon_nam(mtmp)),
helm_simple_name(obj));
#else
if (youmonst.data->mlet == S_EEL
|| u.umonnum == PM_TRAPPER)
pline(
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"Wait, %s! There's a hidden %s named %s there!",
m_monnam(mtmp), youmonst.data->mname, plname);
#else
#endif
else
pline(
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"Wait, %s! There's a %s named %s hiding under %s!",
m_monnam(mtmp), youmonst.data->mname, plname,
doname(level.objects[u.ux][u.uy]));
}
/* hero might be a mimic, concealed via #monster */
- if (youmonst.data->mlet == S_MIMIC && youmonst.m_ap_type && !range2
+ if (youmonst.data->mlet == S_MIMIC && U_AP_TYPE && !range2
&& foundyou && !u.uswallow) {
boolean sticky = sticks(youmonst.data);
*/
pline("\89½\8eÒ\82©\82ª\82 \82È\82½\82Ì\8fã\82É\82Ì\82µ\82©\82©\82Á\82½\81D");
else /* see note about m_monnam() above */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Wait, %s! That's a %s named %s!", m_monnam(mtmp),
youmonst.data->mname, plname);
#else
}
/* non-mimic hero might be mimicking an object after eating m corpse */
- if (youmonst.m_ap_type == M_AP_OBJECT && !range2 && foundyou
- && !u.uswallow) {
+ if (U_AP_TYPE == M_AP_OBJECT && !range2 && foundyou && !u.uswallow) {
if (!canspotmon(mtmp))
map_invisible(mtmp->mx, mtmp->my);
if (!youseeit)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s!", Something, (likes_gold(mtmp->data)
&& youmonst.mappearance == GOLD_PIECE)
? "tries to pick you up"
: "\96³\8e\8b\82µ\82½");
#endif
else /* see note about m_monnam() above */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Wait, %s! That %s is really %s named %s!", m_monnam(mtmp),
mimic_obj_name(&youmonst), an(mons[u.umonnum].mname),
plname);
if (multi < 0) { /* this should always be the case */
char buf[BUFSZ];
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(buf, "You appear to be %s again.",
Upolyd ? (const char *) an(youmonst.data->mname)
: (const char *) "yourself");
if (u.uinvulnerable) {
/* monsters won't attack you */
- if (mtmp == u.ustuck)
+ if (mtmp == u.ustuck) {
/*JP
pline("%s loosens its grip slightly.", Monnam(mtmp));
*/
pline("%s\82Í\92÷\82ß\82Â\82¯\82ð\82í\82¸\82©\82É\8aÉ\82ß\82½\81D", Monnam(mtmp));
- else if (!range2) {
+ } else if (!range2) {
if (youseeit || sensemon(mtmp))
/*JP
pline("%s starts to attack you, but pulls back.",
*/
pline("%s\82Í\93Ë\90i\82µ\81C\96ß\82Á\82½\81I", Monnam(mtmp));
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_hear("a %s nearby.",
is_whirly(mtmp->data) ? "rushing noise"
: "splat");
protection might fail (33% chance) when the armor is cursed */
if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK)
&& (!obj->cursed || rn2(3))) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s your %s %s!", Monnam(mtmp),
(mattk->adtyp == AD_WRAP) ? "slips off of"
: "grabs you, but cannot hold onto",
{
struct permonst *mdat = mtmp->data;
int uncancelled, ptmp;
- int dmg, armpro, permdmg;
+ int dmg, armpro, permdmg, tmphp;
char buf[BUFSZ];
struct permonst *olduasmon = youmonst.data;
int res;
}
} else if (u.ustuck == mtmp) {
exercise(A_STR, FALSE);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("are being %s.", (mtmp->data == &mons[PM_ROPE_GOLEM])
? "choked"
: "crushed");
if (otmp->otyp == CORPSE
&& touch_petrifies(&mons[otmp->corpsenm])) {
dmg = 1;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s hits you with the %s corpse.", Monnam(mtmp),
mons[otmp->corpsenm].mname);
#else
goto dopois;
case AD_DRCO:
ptmp = A_CON;
- dopois:
+ dopois:
hitmsg(mtmp, mattk);
if (uncancelled && !rn2(8)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)),
mpoisons_subj(mtmp, mattk));
#else
/* This case is too obvious to ignore, but Nethack is not in
* general very good at considering height--most short monsters
* still _can_ attack you when you're flying or mounted.
- * [FIXME: why can't a flying attacker overcome this?]
*/
- if (u.usteed || Levitation || Flying) {
+ if ((u.usteed || Levitation || Flying) && !is_flyer(mtmp->data)) {
/*JP
pline("%s tries to reach your %s %s!", Monst_name, sidestr, leg);
*/
Monst_name, sidestr, leg);
#endif
} else if (!rn2(5)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s pricks through your %s boot!", Monst_name,
sidestr);
#else
sidestr);
#endif
} else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s scratches your %s boot!", Monst_name,
sidestr);
#else
You_hear("%s\82ª\83V\83\85\81[\83b\82Æ\82¢\82¤\90º\82ð\95·\82¢\82½\81I", mon_nam(mtmp));
if (!rn2(10)
|| (flags.moonphase == NEW_MOON && !have_lizard())) {
- do_stone:
+ do_stone:
if (!Stoned && !Stone_resistance
&& !(poly_when_stoned(youmonst.data)
&& polymon(PM_STONE_GOLEM))) {
} else {
dmg = 0;
if (flags.verbose)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s brushes against your %s.", Monnam(mtmp),
body_part(LEG));
#else
break;
/* Continue below */
} else if (dmgtype(youmonst.data, AD_SEDU)
- || (SYSOPT_SEDUCE && dmgtype(youmonst.data, AD_SSEX))) {
+ /* !SYSOPT_SEDUCE: when hero is attacking and AD_SSEX
+ is disabled, it would be changed to another damage
+ type, but when defending, it remains as-is */
+ || dmgtype(youmonst.data, AD_SSEX)) {
#if 0 /*JP:T*/
pline("%s %s.", Monnam(mtmp),
- mtmp->minvent
+ Deaf ? "says something but you can't hear it"
+ : mtmp->minvent
? "brags about the goods some dungeon explorer provided"
: "makes some remarks about how difficult theft is lately");
#else
pline("%s\82Í%s\81D", Monnam(mtmp),
- mtmp->minvent
+ Deaf ? "\89½\82©\82ð\8c¾\82Á\82½\82ª\95·\82±\82¦\82È\82©\82Á\82½"
+ : mtmp->minvent
? "\82 \82é\96À\8b{\92T\8c\9f\89Æ\82ª\92u\82¢\82Ä\82Á\82½\95i\95¨\82ð\8e©\96\9d\82µ\82½"
- : "\8dÅ\8bß\90Þ\93\90\82ª\82¢\82©\82É\8d¢\93ï\82©\92W\81X\82Æ\8fq\82×\82½");
+ : "\8dÅ\8bß\90Þ\93\90\82ª\82¢\82©\82É\8d¢\93ï\82©\92W\81X\82Æ\8fq\82×\82½");
#endif
if (!tele_restrict(mtmp))
(void) rloc(mtmp, TRUE);
return 3;
} else if (mtmp->mcan) {
if (!Blind)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s tries to %s you, but you seem %s.",
Adjmonnam(mtmp, "plain"),
flags.female ? "charm" : "seduce",
(void) rloc(mtmp, TRUE);
if (is_animal(mtmp->data) && *buf) {
if (canseemon(mtmp))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s tries to %s away with %s.", Monnam(mtmp),
locomotion(mtmp->data, "run"), buf);
#else
hitmsg(mtmp, mattk);
if (uncancelled) {
if (flags.verbose)
-/*JP
- Your("position suddenly seems very uncertain!");
-*/
- pline("\8e©\95ª\82Ì\82¢\82é\88Ê\92u\82ª\93Ë\91R\95s\96¾\8am\82É\82È\82Á\82½\81I");
+#if 0 /*JP:T*/
+ Your("position suddenly seems %suncertain!",
+ (Teleport_control && !Stunned && !unconscious()) ? ""
+ : "very ");
+#else
+ pline("\8e©\95ª\82Ì\82¢\82é\88Ê\92u\82ª\93Ë\91R%s\95s\96¾\8am\82É\82È\82Á\82½\81I",
+ (Teleport_control && !Stunned && !unconscious()) ? ""
+ : "\82Æ\82Ä\82à");
+#endif
tele();
+ /* As of 3.6.2: make sure damage isn't fatal; previously, it
+ was possible to be teleported and then drop dead at
+ the destination when QM's 1d4 damage gets applied below;
+ even though that wasn't "wrong", it seemed strange,
+ particularly if the teleportation had been controlled
+ [applying the damage first and not teleporting if fatal
+ is another alternative but it has its own complications] */
+ if ((Half_physical_damage ? (dmg - 1) / 2 : dmg)
+ >= (tmphp = (Upolyd ? u.mh : u.uhp))) {
+ dmg = tmphp - 1;
+ if (Half_physical_damage)
+ dmg *= 2; /* doesn't actually increase damage; we only
+ * get here if half the original damage would
+ * would have been fatal, so double reduced
+ * damage will be less than original damage */
+ if (dmg < 1) { /* implies (tmphp <= 1) */
+ dmg = 1;
+ /* this might increase current HP beyond maximum HP but
+ it will be immediately reduced below, so that should
+ be indistinguishable from zero damage; we don't drop
+ damage all the way to zero because that inhibits any
+ passive counterattack if poly'd hero has one */
+ if (Upolyd && u.mh == 1)
+ ++u.mh;
+ else if (!Upolyd && u.uhp == 1)
+ ++u.uhp;
+ /* [don't set context.botl here] */
+ }
+ }
}
break;
case AD_RUST:
if (!engulf_target(mtmp, &youmonst))
return 0;
- if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)))
- && sobj_at(BOULDER, u.ux, u.uy))
+ if ((t && is_pit(t->ttyp)) && sobj_at(BOULDER, u.ux, u.uy))
return 0;
if (Punished)
* like horses for now :-)
*/
Strcpy(buf, mon_nam(u.usteed));
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s lunges forward and plucks you off %s!", Monnam(mtmp),
buf);
#else
You("%s\82©\82ç\89ð\95ú\82³\82ê\82½\81I",
u.utraptype == TT_WEB ? "\82\82à\82Ì\91\83" : "ã©");
#endif
- u.utrap = 0;
+ reset_utrap(FALSE);
}
i = number_leashed();
if (i > 0) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
const char *s = (i > 1) ? "leashes" : "leash";
pline_The("%s %s loose.", s, vtense(s, "snap"));
if (Punished)
placebc();
u.ustuck = 0;
- return (mtmp->mhp > 0) ? 0 : 2;
+ return (!DEADMONSTER(mtmp)) ? 0 : 2;
}
display_nhwindow(WIN_MESSAGE, FALSE);
if (mtmp != u.ustuck)
return 0;
+ if (Punished) {
+ /* ball&chain are in limbo while swallowed; update their internal
+ location to be at swallower's spot */
+ if (uchain->where == OBJ_FREE)
+ uchain->ox = mtmp->mx, uchain->oy = mtmp->my;
+ if (uball->where == OBJ_FREE)
+ uball->ox = mtmp->mx, uball->oy = mtmp->my;
+ }
if (u.uswldtim > 0)
u.uswldtim -= 1;
if (Half_physical_damage)
tmp *= 2; /* sorry */
} else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s%s digests you!", Monnam(mtmp),
(u.uswldtim == 2) ? " thoroughly"
: (u.uswldtim == 1) ? " utterly" : "");
case AD_PHYS:
physical_damage = TRUE;
if (mtmp->data == &mons[PM_FOG_CLOUD]) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("are laden with moisture and %s",
flaming(youmonst.data)
? "are smoldering out!"
if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj *) 0)) {
if (!Blind) {
long was_blinded = Blinded;
+
if (!Blinded)
/*JP
You_cant("see in here!");
if (tmp)
stop_occupation();
- if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
-#if 0 /*JP*/
+ if (!u.uswallow) {
+ ; /* life-saving has already expelled swallowed hero */
+ } else if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
+#if 0 /*JP:T*/
pline("%s very hurriedly %s you!", Monnam(mtmp),
is_animal(mtmp->data) ? "regurgitates" : "expels");
#else
#endif
expels(mtmp, mtmp->data, FALSE);
} else if (!u.uswldtim || youmonst.data->msize >= MZ_HUGE) {
+ /* As of 3.6.2: u.uswldtim used to be set to 0 by life-saving but it
+ expels now so the !u.uswldtim case is no longer possible;
+ however, polymorphing into a huge form while already
+ swallowed is still possible */
/*JP
You("get %s!", is_animal(mtmp->data) ? "regurgitated" : "expelled");
*/
if (mtmp->mcan)
return 0;
- if (!ufound)
-#if 0 /*JP*/
+ if (!ufound) {
+#if 0 /*JP:T*/
pline("%s explodes at a spot in %s!",
canseemon(mtmp) ? Monnam(mtmp) : "It",
levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water"
levl[mtmp->mux][mtmp->muy].typ == WATER ? "\90\85\92\86"
: "\8bó\8aÔ");
#endif
- else {
+ } else {
int tmp = d((int) mattk->damn, (int) mattk->damd);
boolean not_affected = defends((int) mattk->adtyp, uwep);
case AD_ELEC:
physical_damage = FALSE;
not_affected |= Shock_resistance;
- common:
+ goto common;
+ case AD_PHYS:
+ /* there aren't any exploding creatures with AT_EXPL attack
+ for AD_PHYS damage but there might be someday; without this,
+ static analysis complains that 'physical_damage' is always
+ False when tested below; it's right, but having that in
+ place means one less thing to update if AD_PHYS gets added */
+ common:
if (!not_affected) {
if (ACURR(A_DEX) > rnd(20)) {
if (kill_agr)
mondead(mtmp);
wake_nearto(mtmp->mx, mtmp->my, 7 * 7);
- return (mtmp->mhp > 0) ? 0 : 2;
+ return (!DEADMONSTER(mtmp)) ? 0 : 2;
}
/* monster gazes at you */
struct attack *mattk;
{
static const char *const reactions[] = {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"confused", /* [0] */
"stunned", /* [1] */
"puzzled", "dazzled", /* [2,3] */
if (cancelled || !mtmp->mcansee) {
if (!canseemon(mtmp))
break; /* silently */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s.", Monnam(mtmp),
(mtmp->data == &mons[PM_MEDUSA] && mtmp->mcan)
? "doesn't look all that ugly"
break;
if (!m_canseeu(mtmp)) { /* probably you're invisible */
if (useeit)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline(
"%s doesn't seem to notice that %s gaze was reflected.",
Monnam(mtmp), mhis(mtmp));
stoned = TRUE;
killed(mtmp);
- if (mtmp->mhp > 0)
+ if (!DEADMONSTER(mtmp))
break;
return 2;
}
react = rn2(SIZE(reactions));
/* cancelled/hallucinatory feedback; monster might look "confused",
"stunned",&c but we don't actually set corresponding attribute */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s looks %s%s.", Monnam(mtmp),
!rn2(3) ? "" : already ? "quite "
: (!rn2(2) ? "a bit " : "somewhat "),
int
could_seduce(magr, mdef, mattk)
struct monst *magr, *mdef;
-struct attack *mattk;
+struct attack *mattk; /* non-Null: current attack; Null: general capability */
{
struct permonst *pagr;
boolean agrinvis, defperc;
xchar genagr, gendef;
+ int adtyp;
if (is_animal(magr->data))
return 0;
gendef = gender(mdef);
}
- if (agrinvis && !defperc
- && (!SYSOPT_SEDUCE || (mattk && mattk->adtyp != AD_SSEX)))
+ adtyp = mattk ? mattk->adtyp
+ : dmgtype(pagr, AD_SSEX) ? AD_SSEX
+ : dmgtype(pagr, AD_SEDU) ? AD_SEDU
+ : AD_PHYS;
+ if (adtyp == AD_SSEX && !SYSOPT_SEDUCE)
+ adtyp = AD_SEDU;
+
+ if (agrinvis && !defperc && adtyp == AD_SEDU)
return 0;
- if (pagr->mlet != S_NYMPH
- && ((pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS])
- || (SYSOPT_SEDUCE && mattk && mattk->adtyp != AD_SSEX)))
+ /* nymphs have two attacks, one for steal-item damage and the other
+ for seduction, both pass the could_seduce() test;
+ incubi/succubi have three attacks, their claw attacks for damage
+ don't pass the test */
+ if ((pagr->mlet != S_NYMPH
+ && pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS])
+ || (adtyp != AD_SEDU && adtyp != AD_SSEX && adtyp != AD_SITM))
return 0;
- if (genagr == 1 - gendef)
- return 1;
- else
- return (pagr->mlet == S_NYMPH) ? 2 : 0;
+ return (genagr == 1 - gendef) ? 1 : (pagr->mlet == S_NYMPH) ? 2 : 0;
}
-/* Returns 1 if monster teleported */
+/* returns 1 if monster teleported (or hero leaves monster's vicinity) */
int
doseduce(mon)
struct monst *mon;
{
struct obj *ring, *nring;
boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */
+ boolean seewho, naked; /* True iff no armor */
int attr_tot, tried_gloves = 0;
- char qbuf[QBUFSZ];
+ char qbuf[QBUFSZ], Who[QBUFSZ];
if (mon->mcan || mon->mspec_used) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s acts as though %s has got a %sheadache.", Monnam(mon),
mhe(mon), mon->mcan ? "severe " : "");
#else
#endif
return 0;
}
-
if (unconscious()) {
/*JP
pline("%s seems dismayed at your lack of response.", Monnam(mon));
pline("%s\82Í\95Ô\8e\96\82ª\82È\82¢\82Ì\82Å\8bC\82ª\88Þ\82¦\82½\82æ\82¤\82¾\81D", Monnam(mon));
return 0;
}
-
- if (Blind)
+ seewho = canseemon(mon);
+ if (!seewho)
/*JP
- pline("It caresses you...");
+ pline("Someone caresses you...");
*/
pline("\89½\8eÒ\82©\82ª\82 \82È\82½\82ð\95ø\82«\82µ\82ß\82Ä\82¢\82é\81D\81D\81D");
else
You_feel("very attracted to %s.", mon_nam(mon));
*/
You("%s\82É\88ø\82«\82Â\82¯\82ç\82ê\82Ä\82é\82æ\82¤\82È\8bC\82ª\82µ\82½\81D", mon_nam(mon));
+ /* cache the seducer's name in a local buffer */
+/*JP
+ Strcpy(Who, (!seewho ? (fem ? "She" : "He") : Monnam(mon)));
+*/
+ Strcpy(Who, (!seewho ? (fem ? "\94Þ\8f\97" : "\94Þ") : Monnam(mon)));
+
/* if in the process of putting armor on or taking armor off,
interrupt that activity now */
(void) stop_donning((struct obj *) 0);
/* don't take off worn ring if gloves are in the way */
if (!tried_gloves++)
/*JP
- mayberem(uarmg, "gloves");
+ mayberem(mon, Who, uarmg, "gloves");
*/
- mayberem(uarmg, "\8f¬\8eè");
+ mayberem(mon, Who, uarmg, "\8f¬\8eè");
if (uarmg)
continue; /* next ring might not be worn */
}
- if (rn2(20) < ACURR(A_CHA)) {
-#if 0 /*JP*/
+ /* confirmation prompt when charisma is high bypassed if deaf */
+ if (!Deaf && rn2(20) < ACURR(A_CHA)) {
+#if 0 /*JP:T*/
(void) safe_qbuf(qbuf, "\"That ",
" looks pretty. May I have it?\"", ring,
xname, simpleonames, "ring");
if (yn(qbuf) == 'n')
continue;
} else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s decides she'd like %s, and takes it.",
- Blind ? "She" : Monnam(mon), yname(ring));
+ Who, yname(ring));
#else
pline("%s\82Í%s\82ª\82Æ\82Ä\82à\8bC\82É\82¢\82Á\82Ä\81C\82»\82ê\82ð\8eæ\82è\82 \82°\82½\81D",
- Blind ? "\94Þ\8f\97" : Monnam(mon), xname(ring));
+ Who, xname(ring));
#endif
makeknown(RIN_ADORNMENT);
- if (ring == uleft || ring == uright)
- Ring_gone(ring);
- if (ring == uwep)
- setuwep((struct obj *) 0);
- if (ring == uswapwep)
- setuswapwep((struct obj *) 0);
- if (ring == uquiver)
- setuqwep((struct obj *) 0);
+ /* might be in left or right ring slot or weapon/alt-wep/quiver */
+ if (ring->owornmask)
+ remove_worn_item(ring, FALSE);
freeinv(ring);
(void) mpickobj(mon, ring);
} else {
/* don't put on ring if gloves are in the way */
if (!tried_gloves++)
/*JP
- mayberem(uarmg, "gloves");
+ mayberem(mon, Who, uarmg, "gloves");
*/
- mayberem(uarmg, "\8f¬\8eè");
+ mayberem(mon, Who, uarmg, "\8f¬\8eè");
if (uarmg)
break; /* no point trying further rings */
}
- if (rn2(20) < ACURR(A_CHA)) {
-#if 0 /*JP*/
+ /* confirmation prompt when charisma is high bypassed if deaf */
+ if (!Deaf && rn2(20) < ACURR(A_CHA)) {
+#if 0 /*JP:T*/
(void) safe_qbuf(qbuf, "\"That ",
- " looks pretty. Would you wear it for me?\"",
+ " looks pretty. Would you wear it for me?\"",
ring, xname, simpleonames, "ring");
#else
(void) safe_qbuf(qbuf, "\81u\82¨\82â\82È\82ñ\82Ä\82·\82Î\82ç\82µ\82¢",
if (yn(qbuf) == 'n')
continue;
} else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s decides you'd look prettier wearing %s,",
- Blind ? "He" : Monnam(mon), yname(ring));
+ Who, yname(ring));
#else
pline("%s\82Í%s\82ð\82Â\82¯\82½\82 \82È\82½\82ª\82æ\82è\96£\97Í\93I\82¾\82Æ\8dl\82¦\81C",
- Blind ? "\94Þ" : Monnam(mon), xname(ring));
+ Who, xname(ring));
#endif
/*JP
pline("and puts it on your finger.");
}
makeknown(RIN_ADORNMENT);
if (!uright) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s puts %s on your right %s.",
- Blind ? "He" : Monnam(mon), the(xname(ring)),
- body_part(HAND));
+ Who, the(xname(ring)), body_part(HAND));
#else
pline("%s\82Í%s\82ð\82 \82È\82½\82Ì\89E%s\82É\82Í\82ß\82½\81D",
- Blind ? "\94Þ" : Monnam(mon), the(xname(ring)),
- body_part(HAND));
+ Who, the(xname(ring)), body_part(HAND));
#endif
setworn(ring, RIGHT_RING);
} else if (!uleft) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s puts %s on your left %s.",
- Blind ? "He" : Monnam(mon), the(xname(ring)),
- body_part(HAND));
+ Who, the(xname(ring)), body_part(HAND));
#else
pline("%s\82Í%s\82ð\82 \82È\82½\82Ì\8d¶%s\82É\82Í\82ß\82½\81D",
- Blind ? "\94Þ" : Monnam(mon), the(xname(ring)),
- body_part(HAND));
+ Who, the(xname(ring)), body_part(HAND));
#endif
setworn(ring, LEFT_RING);
} else if (uright && uright->otyp != RIN_ADORNMENT) {
-#if 0 /*JP*/
- pline("%s replaces %s with %s.", Blind ? "He" : Monnam(mon),
- yname(uright), yname(ring));
+ /* note: the "replaces" message might be inaccurate if
+ hero's location changes and the process gets interrupted,
+ but trying to figure that out in advance in order to use
+ alternate wording is not worth the effort */
+#if 0 /*JP:T*/
+ pline("%s replaces %s with %s.",
+ Who, yname(uright), yname(ring));
#else
- pline("%s\82Í%s\82ð%s\82É\82Æ\82è\82©\82¦\82½\81D", Blind ? "\94Þ" : Monnam(mon),
- yname(uright), xname(ring));
+ pline("%s\82Í%s\82ð%s\82É\82Æ\82è\82©\82¦\82½\81D",
+ Who, yname(uright), xname(ring));
#endif
Ring_gone(uright);
+ /* ring removal might cause loss of levitation which could
+ drop hero onto trap that transports hero somewhere else */
+ if (u.utotype || distu(mon->mx, mon->my) > 2)
+ return 1;
setworn(ring, RIGHT_RING);
} else if (uleft && uleft->otyp != RIN_ADORNMENT) {
-#if 0 /*JP*/
- pline("%s replaces %s with %s.", Blind ? "He" : Monnam(mon),
- yname(uleft), yname(ring));
+ /* see "replaces" note above */
+#if 0 /*JP:T*/
+ pline("%s replaces %s with %s.",
+ Who, yname(uleft), yname(ring));
#else
- pline("%s\82Í%s\82ð%s\82É\82Æ\82è\82©\82¦\82½\81D", Blind ? "\94Þ" : Monnam(mon),
- yname(uleft), xname(ring));
+ pline("%s\82Í%s\82ð%s\82É\82Æ\82è\82©\82¦\82½\81D",
+ Who, yname(uleft), xname(ring));
#endif
Ring_gone(uleft);
+ if (u.utotype || distu(mon->mx, mon->my) > 2)
+ return 1;
setworn(ring, LEFT_RING);
} else
impossible("ring replacement");
}
}
- if (!uarmc && !uarmf && !uarmg && !uarms && !uarmh && !uarmu)
-#if 0 /*JP*/
- pline("%s murmurs sweet nothings into your ear.",
- Blind ? (fem ? "She" : "He") : Monnam(mon));
-#else
- pline("%s\82Í\82 \82È\82½\82Ì\8e¨\82à\82Æ\82Å\8aÃ\82¢\82³\82³\82â\82«\82ð\82Â\82Ô\82â\82¢\82½\81D",
- Blind ? (fem ? "\94Þ\8f\97" : "\94Þ") : Monnam(mon));
-#endif
- else
-#if 0 /*JP*/
- pline("%s murmurs in your ear, while helping you undress.",
- Blind ? (fem ? "She" : "He") : Monnam(mon));
-#else
- pline("%s\82Í\8e¨\82à\82Æ\82Å\82 \82È\82½\82Ì\95\9e\82ð\92E\82ª\82¹\82È\82ª\82ç\82³\82³\82â\82¢\82½\81D",
- Blind ? (fem ? "\94Þ\8f\97" : "\94Þ") : Monnam(mon));
-#endif
- mayberem(uarmc, cloak_simple_name(uarmc));
+ naked = (!uarmc && !uarmf && !uarmg && !uarms && !uarmh && !uarmu);
+#if 0 /*JP:T*/
+ pline("%s %s%s.", Who,
+ Deaf ? "seems to murmur into your ear"
+ : naked ? "murmurs sweet nothings into your ear"
+ : "murmurs in your ear",
+ naked ? "" : ", while helping you undress");
+#else
+ pline("%s\82Í%s%s\81D", Who,
+ naked ? "" : "\82 \82È\82½\82Ì\95\9e\82ð\92E\82ª\82¹\82È\82ª\82ç",
+ Deaf ? "\8e¨\82à\82Æ\82Å\89½\82©\82Â\82Ô\82â\82¢\82½\82æ\82¤\82¾"
+ : naked ? "\8e¨\82à\82Æ\82Å\8aÃ\82¢\82³\82³\82â\82«\82ð\82Â\82Ô\82â\82¢\82½"
+ : "\82 \82È\82½\82Ì\8e¨\82à\82Æ\82Å\82Â\82Ô\82â\82¢\82½");
+#endif
+ mayberem(mon, Who, uarmc, cloak_simple_name(uarmc));
if (!uarmc)
+ mayberem(mon, Who, uarm, suit_simple_name(uarm));
/*JP
- mayberem(uarm, "suit");
+ mayberem(mon, Who, uarmf, "boots");
*/
- mayberem(uarm, "\83X\81[\83c");
-/*JP
- mayberem(uarmf, "boots");
-*/
- mayberem(uarmf, "\83u\81[\83c");
+ mayberem(mon, Who, uarmf, "\83u\81[\83c");
if (!tried_gloves)
/*JP
- mayberem(uarmg, "gloves");
+ mayberem(mon, Who, uarmg, "gloves");
*/
- mayberem(uarmg, "\8f¬\8eè");
+ mayberem(mon, Who, uarmg, "\8f¬\8eè");
/*JP
- mayberem(uarms, "shield");
+ mayberem(mon, Who, uarms, "shield");
*/
- mayberem(uarms, "\8f\82");
- mayberem(uarmh, helm_simple_name(uarmh));
+ mayberem(mon, Who, uarms, "\8f\82");
+ mayberem(mon, Who, uarmh, helm_simple_name(uarmh));
if (!uarmc && !uarm)
/*JP
- mayberem(uarmu, "shirt");
+ mayberem(mon, Who, uarmu, "shirt");
*/
- mayberem(uarmu, "\83V\83\83\83c");
+ mayberem(mon, Who, uarmu, "\83V\83\83\83c");
+
+ /* removing armor (levitation boots, or levitation ring to make
+ room for adornment ring with incubus case) might result in the
+ hero falling through a trap door or landing on a teleport trap
+ and changing location, so hero might not be adjacent to seducer
+ any more (mayberem() has its own adjacency test so we don't need
+ to check after each potential removal) */
+ if (u.utotype || distu(mon->mx, mon->my) > 2)
+ return 1;
if (uarm || uarmc) {
-#if 0 /*JP*/
- verbalize("You're such a %s; I wish...",
- flags.female ? "sweet lady" : "nice guy");
+ if (!Deaf)
+#if 0 /*JP:T*/
+ verbalize("You're such a %s; I wish...",
+ flags.female ? "sweet lady" : "nice guy");
#else
- verbalize("%s\82¾\81D\81D\81D\82Æ\82¢\82¢\82Ì\82É\81D",
- flags.female ? "\83`\83\83\81[\83~\83\93\83O" : "\82·\82Ä\82«");
+ verbalize("%s\82¾\81D\81D\81D\82Æ\82¢\82¢\82Ì\82É\81D",
+ flags.female ? "\83`\83\83\81[\83~\83\93\83O" : "\82·\82Ä\82«");
#endif
+ else if (seewho)
+/*JP
+ pline("%s appears to sigh.", Monnam(mon));
+*/
+ pline("%s\82Í\82½\82ß\91§\82ð\82Â\82¢\82½\82æ\82¤\82¾\81D", Monnam(mon));
+ /* else no regret message if can't see or hear seducer */
+
if (!tele_restrict(mon))
(void) rloc(mon, TRUE);
return 1;
if (mon->mtame) { /* don't charge */
;
} else if (rn2(20) < ACURR(A_CHA)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s demands that you pay %s, but you refuse...",
- noit_Monnam(mon), Blind ? (fem ? "her" : "him") : mhim(mon));
+ noit_Monnam(mon), noit_mhim(mon));
#else
pline("%s\82Í\82 \82È\82½\82É\8bà\82ð\95¥\82¤\82æ\82¤\97v\8b\81\82µ\82½\82ª\81C\82 \82È\82½\82Í\8b\91\82ñ\82¾\81D\81D\81D",
noit_Monnam(mon));
*/
verbalize("\82±\82ê\82Í\82¨\82²\82è%s\81I", fem ? "\82æ" : "\82³");
} else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s takes %ld %s for services rendered!", noit_Monnam(mon),
cost, currency(cost));
#else
}
STATIC_OVL void
-mayberem(obj, str)
+mayberem(mon, seducer, obj, str)
+struct monst *mon;
+const char *seducer; /* only used for alternate message */
struct obj *obj;
const char *str;
{
if (!obj || !obj->owornmask)
return;
+ /* removal of a previous item might have sent the hero elsewhere
+ (loss of levitation that leads to landing on a transport trap) */
+ if (u.utotype || distu(mon->mx, mon->my) > 2)
+ return;
- if (rn2(20) < ACURR(A_CHA)) {
-#if 0 /*JP*/
+ /* being deaf overrides confirmation prompt for high charisma */
+ if (Deaf) {
+/*JP
+ pline("%s takes off your %s.", seducer, str);
+*/
+ pline("%s\82Í\82 \82È\82½\82Ì%s\82ð\92E\82ª\82¹\82½\81D", seducer, str);
+ } else if (rn2(20) < ACURR(A_CHA)) {
+#if 0 /*JP:T*/
Sprintf(qbuf, "\"Shall I remove your %s, %s?\"", str,
(!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart"));
#else
} else {
char hairbuf[BUFSZ];
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(hairbuf, "let me run my fingers through your %s",
body_part(HAIR));
#else
flags.female ? "\82È\82ñ\82ÄãY\97í\82È%s\82È\82ñ\82¾" : "\8a\95\82ð\8eæ\82Á\82½\82ç\82È\82©\82È\82©\83C\83J\83X\82¶\82á\82È\82¢",
body_part(HAIR));
#endif
-#if 0 /*JP*/
+#if 0 /*JP:T*/
verbalize("Take off your %s; %s.", str,
(obj == uarm)
? "let's get a little closer"
switch (oldu_mattk->adtyp) {
case AD_ACID:
if (!rn2(2)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s is splashed by %s%s!", Monnam(mtmp),
/* temporary? hack for sequencing issue: "your acid"
looks strange coming immediately after player has
pline("%s\82Í\90Î\82É\82È\82Á\82½\81I", Monnam(mtmp));
stoned = 1;
xkilled(mtmp, XKILL_NOMSG);
- if (mtmp->mhp > 0)
+ if (!DEADMONSTER(mtmp))
return 1;
return 2;
}
case AD_STUN: /* Yellow mold */
if (!mtmp->mstun) {
mtmp->mstun = 1;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s.", Monnam(mtmp),
makeplural(stagger(mtmp->data, "stagger")));
#else
case AD_FIRE: /* Red mold */
if (resists_fire(mtmp)) {
shieldeff(mtmp->mx, mtmp->my);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s is mildly warm.", Monnam(mtmp));
#else
pline("%s\82Í\92g\82©\82\82È\82Á\82½\81D", Monnam(mtmp));
tmp = 0;
break;
}
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s is suddenly very hot!", Monnam(mtmp));
#else
pline("%s\82Í\93Ë\91R\94M\82\82È\82Á\82½\81I", Monnam(mtmp));
case AD_ELEC:
if (resists_elec(mtmp)) {
shieldeff(mtmp->mx, mtmp->my);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s is slightly tingled.", Monnam(mtmp));
#else
pline("%s\82Í\82¿\82å\82Á\82Æ\83s\83\8a\83s\83\8a\82µ\82½\81D", Monnam(mtmp));
tmp = 0;
break;
}
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s is jolted with your electricity!", Monnam(mtmp));
#else
pline("%s\82Í\93d\8bC\83V\83\87\83b\83N\82ð\82¤\82¯\82½\81I", Monnam(mtmp));
else
tmp = 0;
-assess_dmg:
+ assess_dmg:
if ((mtmp->mhp -= tmp) <= 0) {
/*JP
pline("%s dies!", Monnam(mtmp));
*/
pline("%s\82Í\8e\80\82ñ\82¾\81I", Monnam(mtmp));
xkilled(mtmp, XKILL_NOMSG);
- if (mtmp->mhp > 0)
+ if (!DEADMONSTER(mtmp))
return 1;
return 2;
}