-/* NetHack 3.6 dokick.c $NHDT-Date: 1517128663 2018/01/28 08:37:43 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.113 $ */
+/* NetHack 3.6 dokick.c $NHDT-Date: 1575245057 2019/12/02 00:04:17 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.136 $ */
/* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */
/* 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-2023 */
/* JNetHack may be freely redistributed. See license for details. */
#include "hack.h"
*/
static const char kick_passes_thru[] = "\8fR\82è\82Í\83_\83\81\81[\83W\82ð\97^\82¦\82¸\82É\82·\82è\94²\82¯\82½";
+/* kicking damage when not poly'd into a form with a kick attack */
STATIC_OVL void
kickdmg(mon, clumsy)
-register struct monst *mon;
-register boolean clumsy;
+struct monst *mon;
+boolean clumsy;
{
- register int mdx, mdy;
- register int dmg = (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 15;
- int kick_skill = P_NONE;
- int blessed_foot_damage = 0;
+ int mdx, mdy;
+ int dmg = (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 15;
+ int specialdmg, kick_skill = P_NONE;
boolean trapkilled = FALSE;
if (uarmf && uarmf->otyp == KICKING_BOOTS)
if (thick_skinned(mon->data))
dmg = 0;
- /* attacking a shade is useless */
+ /* attacking a shade is normally useless */
if (mon->data == &mons[PM_SHADE])
dmg = 0;
- if ((is_undead(mon->data) || is_demon(mon->data) || is_vampshifter(mon))
- && uarmf && uarmf->blessed)
- blessed_foot_damage = 1;
+ specialdmg = special_dmgval(&youmonst, mon, W_ARMF, (long *) 0);
- if (mon->data == &mons[PM_SHADE] && !blessed_foot_damage) {
+ if (mon->data == &mons[PM_SHADE] && !specialdmg) {
/*JP
pline_The("%s.", kick_passes_thru);
*/
return;
}
- if (mon->m_ap_type)
+ if (M_AP_TYPE(mon))
seemimic(mon);
check_caitiff(mon);
/* a good kick exercises your dex */
exercise(A_DEX, TRUE);
}
- if (blessed_foot_damage)
- dmg += rnd(4);
+ dmg += specialdmg; /* for blessed (or hypothetically, silver) boots */
if (uarmf)
dmg += uarmf->spe;
dmg += u.udaminc; /* add ring(s) of increase damage */
if (dmg > 0)
mon->mhp -= dmg;
- if (mon->mhp > 0 && martial() && !bigmonst(mon->data) && !rn2(3)
+ if (!DEADMONSTER(mon) && martial() && !bigmonst(mon->data) && !rn2(3)
&& mon->mcanmove && mon != u.ustuck && !mon->mtrapped) {
/* see if the monster has a place to move into */
mdx = mon->mx + u.dx;
}
}
- (void) passive(mon, uarmf, TRUE, mon->mhp > 0, AT_KICK, FALSE);
- if (mon->mhp <= 0 && !trapkilled)
+ (void) passive(mon, uarmf, TRUE, !DEADMONSTER(mon), AT_KICK, FALSE);
+ if (DEADMONSTER(mon) && !trapkilled)
killed(mon);
/* may bring up a dialog, so put this after all messages */
/* reveal hidden target even if kick ends up missing (note: being
hidden doesn't affect chance to hit so neither does this reveal) */
if (mon->mundetected
- || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER)) {
- if (mon->m_ap_type)
+ || (M_AP_TYPE(mon) && M_AP_TYPE(mon) != M_AP_MONSTER)) {
+ if (M_AP_TYPE(mon))
seemimic(mon);
mon->mundetected = 0;
if (!canspotmon(mon))
map_invisible(x, y);
else
newsym(x, y);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
There("is %s here.",
canspotmon(mon) ? a_monnam(mon) : "something hidden");
#else
*/
if (Upolyd && attacktype(youmonst.data, AT_KICK)) {
struct attack *uattk;
- int sum, kickdieroll, armorpenalty,
+ int sum, kickdieroll, armorpenalty, specialdmg,
attknum = 0,
tmp = find_roll_to_hit(mon, AT_KICK, (struct obj *) 0, &attknum,
&armorpenalty);
if (uattk->aatyp != AT_KICK)
continue;
- if (mon->data == &mons[PM_SHADE] && (!uarmf || !uarmf->blessed)) {
+ kickdieroll = rnd(20);
+ specialdmg = special_dmgval(&youmonst, mon, W_ARMF, (long *) 0);
+ if (mon->data == &mons[PM_SHADE] && !specialdmg) {
/* doesn't matter whether it would have hit or missed,
and shades have no passive counterattack */
/*JP
*/
You("%s\82ð\8fR\82Á\82½\82ª\81C%s\81D", mon_nam(mon), kick_passes_thru);
break; /* skip any additional kicks */
- } else if (tmp > (kickdieroll = rnd(20))) {
+ } else if (tmp > kickdieroll) {
/*JP
You("kick %s.", mon_nam(mon));
*/
You("%s\82ð\8fR\82Á\82½\81D", mon_nam(mon));
- sum = damageum(mon, uattk);
+ sum = damageum(mon, uattk, specialdmg);
(void) passive(mon, uarmf, (boolean) (sum > 0),
(sum != 2), AT_KICK, FALSE);
if (sum == 2)
else if (uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25))
clumsy = TRUE;
-doit:
+ doit:
/*JP
You("kick %s.", mon_nam(mon));
*/
robbed -= value;
if (robbed < 0L)
robbed = 0L;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline_The("amount %scovers %s recent losses.",
!robbed ? "" : "partially ", mhis(mtmp));
#else
} else {
if (mtmp->mpeaceful) {
ESHK(mtmp)->credit += value;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("have %ld %s in credit.", ESHK(mtmp)->credit,
currency(ESHK(mtmp)->credit));
#else
out of the vault. If he did do that, player
could try fighting, then weasle out of being
killed by throwing his/her gold when losing. */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
verbalize(
umoney
? "Drop the rest and follow me."
You("%ld%s\95ª\82Ì\91¹\8aQ\82ð\82Ð\82«\82¨\82±\82µ\82½\81I", loss, currency(loss));
make_angry_shk(shkp, x, y);
} else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("owe %s %ld %s for objects destroyed.", mon_nam(shkp), loss,
currency(loss));
#else
return 0;
if ((trap = t_at(x, y)) != 0) {
- if (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !Passes_walls)
- || trap->ttyp == WEB) {
+ if ((is_pit(trap->ttyp) && !Passes_walls) || trap->ttyp == WEB) {
if (!trap->tseen)
find_trap(trap);
#if 0 /*JP:T*/
You_cant("kick %s that's in a %s!", something,
- Hallucination ? "tizzy" :
- (trap->ttyp == WEB) ? "web" : "pit");
+ Hallucination ? "tizzy"
+ : (trap->ttyp == WEB) ? "web"
+ : "pit");
#else
You("%s\82Å\82Í%s\82ð\8fR\82é\82±\82Æ\82ª\82Å\82«\82È\82¢\81I",
Hallucination ? "\8d¬\97\90\82µ\82½\8fó\91Ô" :
if (!uarmf && kickedobj->otyp == CORPSE
&& touch_petrifies(&mons[kickedobj->corpsenm]) && !Stone_resistance) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("kick %s with your bare %s.",
corpse_xname(kickedobj, (const char *) 0, CXN_PFX_THE),
makeplural(body_part(FOOT)));
}
}
- /* range < 2 means the object will not move. */
- /* maybe dexterity should also figure here. */
- range = (int) ((ACURRSTR) / 2 - kickedobj->owt / 40);
+ isgold = (kickedobj->oclass == COIN_CLASS);
+ {
+ int k_owt = (int) kickedobj->owt;
+
+ /* for non-gold stack, 1 item will be split off below (unless an
+ early return occurs, so we aren't moving the split to here);
+ calculate the range for that 1 rather than for the whole stack */
+ if (kickedobj->quan > 1L && !isgold) {
+ long save_quan = kickedobj->quan;
+
+ kickedobj->quan = 1L;
+ k_owt = weight(kickedobj);
+ kickedobj->quan = save_quan;
+ }
+
+ /* range < 2 means the object will not move
+ (maybe dexterity should also figure here) */
+ range = ((int) ACURRSTR) / 2 - k_owt / 40;
+ }
if (martial())
range += rnd(3);
costly = (!(kickedobj->no_charge && !Has_contents(kickedobj))
&& (shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0
&& costly_spot(x, y));
- isgold = (kickedobj->oclass == COIN_CLASS);
if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
if ((!martial() && rn2(20) > ACURR(A_DEX))
*/
pline("\82Ñ\82\82Æ\82à\82µ\82È\82¢\81D");
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %sn't come loose.",
The(distant_name(kickedobj, xname)),
otense(kickedobj, "do"));
*/
pline("\89½\82©\82ª\8aÉ\82ñ\82Å\82Æ\82ê\82½\81D");
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s loose.", The(distant_name(kickedobj, xname)),
otense(kickedobj, "come"));
#else
kickedobj = splitobj(kickedobj, 1L);
} else {
if (rn2(20)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
static NEARDATA const char *const flyingcoinmsg[] = {
"scatter the coins", "knock coins all over the place",
"send coins flying in all directions",
}
if (slide && !Blind)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Whee! %s %s across the %s.", Doname2(kickedobj),
otense(kickedobj, "slide"), surface(x, y));
#else
if (wl == BOTH_SIDES)
bp = makeplural(bp);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Your("%s%s %s in no shape for kicking.",
(wl == LEFT_SIDE) ? "left " : (wl == RIGHT_SIDE) ? "right " : "",
bp, (wl == BOTH_SIDES) ? "are" : "is");
kick_monster(mtmp, x, y);
glyph = glyph_at(x, y);
/* see comment in attack_checks() */
- if (mtmp->mhp <= 0) { /* DEADMONSTER() */
+ if (DEADMONSTER(mtmp)) { /* DEADMONSTER() */
/* if we mapped an invisible monster and immediately
killed it, we don't want to forget what we thought
was there before the kick */
/*JP
You("splash some %s around.", hliquid("water"));
*/
- You("%s\82ð\89ñ\82è\82É\82Ü\82«\82¿\82ç\82µ\82½\81D", hliquid("water"));
+ You("%s\82ð\89ñ\82è\82É\82Ü\82«\82¿\82ç\82µ\82½\81D", hliquid("\90\85"));
return 1;
}
if (maploc->typ == SDOOR) {
if (!Levitation && rn2(30) < avrg_attrib) {
cvt_sdoor_to_door(maploc); /* ->typ = DOOR */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Crash! %s a secret door!",
/* don't "kick open" when it's locked
unless it also happens to be trapped */
return 1;
} else if (!rn2(4)) {
if (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)) {
- fall_through(FALSE);
+ fall_through(FALSE, 0);
return 1;
} else
goto ouch;
You("kick %s.", (Blind ? something : "the altar"));
*/
You("%s\82ð\8fR\82Á\82½\81D", (Blind ? "\89½\82©" : "\8dÕ\92d"));
+ altar_wrath(x, y);
if (!rn2(3))
goto ouch;
- altar_wrath(x, y);
exercise(A_DEX, TRUE);
return 1;
}
(void) mksobj_at(ROCK, x, y, TRUE, FALSE);
del_engr_at(x, y);
if (Blind)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Crack! %s broke!", Something);
#else
pline("\83S\83c\83\93\81I\89½\82©\82ª\89ó\82ê\82½\81I");
/* nothing, fruit or trouble? 75:23.5:1.5% */
if (rn2(3)) {
if (!rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_hear("a low buzzing."); /* a warning */
#else
You_hear("\82Ô\81[\82ñ\82Æ\82¢\82¤\89¹\82ð\95·\82¢\82½\81D"); /* a warning */
* may not refer to the correct object */
treefruit = mksobj(frtype, TRUE, FALSE);
treefruit->quan = nfruit - nfall;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%ld %s got caught in the branches.",
nfruit - nfall, xname(treefruit));
#else
exercise(A_DEX, TRUE);
return 1;
} else if (!rn2(3)) {
-#if 0 /*JP*/
- pline("Flupp! %s.",
- (Blind ? "You hear a sloshing sound"
- : "Muddy waste pops up from the drain"));
+ if (Blind && Deaf)
+ Sprintf(buf, " %s", body_part(FACE));
+ else
+ buf[0] = '\0';
+#if 0 /*JP:T*/
+ pline("%s%s%s.", !Deaf ? "Flupp! " : "",
+ !Blind
+ ? "Muddy waste pops up from the drain"
+ : !Deaf
+ ? "You hear a sloshing sound" /* Deaf-aware */
+ : "Something splashes you in the", buf);
#else
- pline("\82¤\82í\81I%s\81D",
- (Blind ? "\82 \82È\82½\82Í\81C\83o\83`\83\83\83o\83`\83\83\82·\82é\89¹\82ð\95·\82¢\82½"
- : "\94r\90\85\8cû\82©\82ç\82Ç\82ë\82Ç\82ë\82Ì\94p\8aü\95¨\82ª\8fo\82Ä\82\82é"));
+ /*JP:TODO:\81u\8aç\82É\82©\82©\82Á\82½\81v\82Ì\8cê\8f\87\92²\90® */
+ pline("%s%s\81D", !Deaf ? "\82¤\82í\81I" : "",
+ !Blind
+ ? "\94r\90\85\8cû\82©\82ç\82Ç\82ë\82Ç\82ë\82Ì\94p\8aü\95¨\82ª\8fo\82Ä\82\82é"
+ : !Deaf
+ ? "\82 \82È\82½\82Í\81C\83o\83`\83\83\83o\83`\83\83\82·\82é\89¹\82ð\95·\82¢\82½" /* Deaf-aware */
+ : "\89½\82©\82ª\82 \82È\82½\82É\82©\82©\82Á\82½");
#endif
if (!(maploc->looted & S_LRING)) { /* once per sink */
if (!Blind)
|| IS_STWALL(maploc->typ)) {
if (!IS_STWALL(maploc->typ) && maploc->ladder == LA_DOWN)
goto dumb;
- ouch:
+ ouch:
/*JP
pline("Ouch! That hurts!");
*/
if (maploc->doormask == D_ISOPEN || maploc->doormask == D_BROKEN
|| maploc->doormask == D_NODOOR) {
- dumb:
+ dumb:
exercise(A_DEX, FALSE);
if (martial() || ACURR(A_DEX) >= 16 || rn2(3)) {
/*JP
obj_extract_self(obj);
if (costly) {
- price += stolen_value(
- obj, x, y, (costly_spot(u.ux, u.uy)
- && index(u.urooms, *in_rooms(x, y, SHOPBASE))),
- TRUE);
+ price += stolen_value(obj, x, y,
+ (costly_spot(u.ux, u.uy)
+ && index(u.urooms,
+ *in_rooms(x, y, SHOPBASE))),
+ TRUE);
/* set obj->no_charge to 0 */
if (Has_contents(obj))
picked_container(obj); /* does the right thing */
pline("\8bß\82\82É\82 \82Á\82½%s\82ª%s\97\8e\82¿\82½\81D", what, gate_str);
#endif
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s adjacent %s %s.",
dct == 1L ? "One of the" : "Some of the",
dct == 1L ? "objects falls" : what, gate_str);
}
if (ESHK(shkp)->debit > debit) {
long amt = (ESHK(shkp)->debit - debit);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("owe %s %ld %s for goods lost.", Monnam(shkp), amt,
currency(amt));
#else
/* boulders never fall through trap doors, but they might knock
other things down before plugging the hole */
if (otmp->otyp == BOULDER && ((t = t_at(x, y)) != 0)
- && (t->ttyp == TRAPDOOR || t->ttyp == HOLE)) {
+ && is_hole(t->ttyp)) {
if (impact)
impact_drop(otmp, x, y, 0);
return FALSE; /* let caller finish the drop */
continue;
where = (int) (otmp->owornmask & 0x7fffL); /* destination code */
+ if ((where & MIGR_TO_SPECIES) != 0)
+ continue;
+
nobreak = (where & MIGR_NOBREAK) != 0;
noscatter = (where & MIGR_WITH_HERO) != 0;
where &= ~(MIGR_NOBREAK | MIGR_NOSCATTER);
stackobj(otmp);
if (!noscatter)
(void) scatter(nx, ny, rnd(2), 0, otmp);
+ else
+ newsym(nx, ny);
} else { /* random location */
/* set dummy coordinates because there's no
current position for rloco() to update */
}
}
+void
+deliver_obj_to_mon(mtmp, cnt, deliverflags)
+int cnt;
+struct monst *mtmp;
+unsigned long deliverflags;
+{
+ struct obj *otmp, *otmp2;
+ int where, maxobj = 1;
+ boolean at_crime_scene = In_mines(&u.uz);
+
+ if ((deliverflags & DF_RANDOM) && cnt > 1)
+ maxobj = rnd(cnt);
+ else if (deliverflags & DF_ALL)
+ maxobj = 0;
+ else
+ maxobj = 1;
+
+ cnt = 0;
+ for (otmp = migrating_objs; otmp; otmp = otmp2) {
+ otmp2 = otmp->nobj;
+ where = (int) (otmp->owornmask & 0x7fffL); /* destination code */
+ if ((where & MIGR_TO_SPECIES) == 0)
+ continue;
+
+ if ((mtmp->data->mflags2 & otmp->corpsenm) != 0) {
+ obj_extract_self(otmp);
+ otmp->owornmask = 0L;
+ otmp->ox = otmp->oy = 0;
+
+ /* special treatment for orcs and their kind */
+ if ((otmp->corpsenm & M2_ORC) != 0 && has_oname(otmp)) {
+ if (!has_mname(mtmp)) {
+ if (at_crime_scene || !rn2(2))
+ mtmp = christen_orc(mtmp,
+ at_crime_scene ? ONAME(otmp)
+ : (char *) 0,
+ /* bought the stolen goods */
+ " the Fence");
+ }
+ free_oname(otmp);
+ }
+ otmp->corpsenm = 0;
+ (void) add_to_minv(mtmp, otmp);
+ cnt++;
+ if (maxobj && cnt >= maxobj)
+ break;
+ /* getting here implies DF_ALL */
+ }
+ }
+}
+
STATIC_OVL void
otransit_msg(otmp, nodrop, num)
register struct obj *otmp;
register boolean nodrop;
long num;
{
- char obuf[BUFSZ];
+#if 0 /*JP*/
+ char *optr = 0, obuf[BUFSZ], xbuf[BUFSZ];
+#else
+ char obuf[BUFSZ], xbuf[BUFSZ];
+#endif
#if 0 /*JP*/
- Sprintf(obuf, "%s%s",
- (otmp->otyp == CORPSE && type_is_pname(&mons[otmp->corpsenm]))
- ? ""
- : "The ",
- cxname(otmp));
+ if (otmp->otyp == CORPSE) {
+ /* Tobjnam() calls xname() and would yield "The corpse";
+ we want more specific "The newt corpse" or "Medusa's corpse" */
+ optr = upstart(corpse_xname(otmp, (char *) 0, CXN_PFX_THE));
+ } else {
+ optr = Tobjnam(otmp, (char *) 0);
+ }
+ Strcpy(obuf, optr);
#else
Sprintf(obuf, "%s\82Í", xname(otmp));
#endif
if (num) { /* means: other objects are impacted */
+ /* As of 3.6.2: use a separate buffer for the suffix to avoid risk of
+ overrunning obuf[] (let pline() handle truncation if necessary) */
#if 0 /*JP*/
- Sprintf(eos(obuf), " %s %s object%s", otense(otmp, "hit"),
- num == 1L ? "another" : "other", num > 1L ? "s" : "");
+ Sprintf(xbuf, " %s %s object%s", otense(otmp, "hit"),
+ (num == 1L) ? "another" : "other", (num > 1L) ? "s" : "");
if (nodrop)
- Sprintf(eos(obuf), ".");
+ Sprintf(eos(xbuf), ".");
else
- Sprintf(eos(obuf), " and %s %s.", otense(otmp, "fall"), gate_str);
+ Sprintf(eos(xbuf), " and %s %s.", otense(otmp, "fall"), gate_str);
#else
- Sprintf(eos(obuf), "\91¼\82Ì\95¨\91Ì\82É\96½\92\86\82µ\82Ä");
+ Sprintf(xbuf, "\91¼\82Ì\95¨\91Ì\82É\96½\92\86\82µ\82Ä");
if(nodrop)
- Sprintf(eos(obuf), "\8e~\82Ü\82Á\82½\81D");
+ Sprintf(eos(xbuf), "\8e~\82Ü\82Á\82½\81D");
else
- Sprintf(eos(obuf), "%s\97\8e\82¿\82½\81D", gate_str);
+ Sprintf(eos(xbuf), "%s\97\8e\82¿\82½\81D", gate_str);
#endif
- pline1(obuf);
+ pline("%s%s", obuf, xbuf);
} else if (!nodrop)
/*JP
pline("%s %s %s.", obuf, otense(otmp, "fall"), gate_str);
}
if (((ttmp = t_at(x, y)) != 0 && ttmp->tseen)
- && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)) {
-#if 0 /*JP*/
+ && is_hole(ttmp->ttyp)) {
+#if 0 /*JP:T*/
gate_str = (ttmp->ttyp == TRAPDOOR) ? "through the trap door"
: "through the hole";
#else