-/* NetHack 3.6 zap.c $NHDT-Date: 1551395521 2019/02/28 23:12:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.307 $ */
+/* NetHack 3.6 zap.c $NHDT-Date: 1573688696 2019/11/13 23:44:56 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.316 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */
/* 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"
const char *const flash_types[] = /* also used in buzzmu(mcastu.c) */
{
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"magic missile", /* Wands must be 0-9 */
"bolt of fire", "bolt of cold", "sleep ray", "death ray",
"bolt of lightning", "", "", "", "",
"",
#endif
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"magic missile", /* Spell equivalents must be 10-19 */
"fireball", "cone of cold", "sleep ray", "finger of death",
"bolt of lightning", /* there is no spell, used for retribution */
"",
#endif
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"blast of missiles", /* Dragon breath equivalents 20-29*/
"blast of fire", "blast of frost", "blast of sleep gas",
"blast of disintegration", "blast of lightning",
if (obj->dknown)
makeknown(obj->otyp);
}
+ update_inventory();
}
}
} else if ((obj = which_armor(mtmp, W_SADDLE)) != 0) {
char buf[BUFSZ];
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)),
distant_name(obj, xname));
#else
if (cansee(mtmp->mx, mtmp->my)) {
if (!canspotmon(mtmp))
Strcpy(buf, An(distant_name(obj, xname)));
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s falls to the %s.", buf,
surface(mtmp->mx, mtmp->my));
#else
} else
mimic_hit_msg(mtmp, otyp);
} else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s looks%s better.", Monnam(mtmp),
otyp == SPE_EXTRA_HEALING ? " much" : "");
#else
(void) display_minventory(mtmp, MINV_ALL | MINV_NOLET | PICK_NONE,
(char *) 0);
} else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s is not carrying anything%s.", noit_Monnam(mtmp),
(u.uswallow && mtmp == u.ustuck) ? " besides you" : "");
#else
coord *cc;
boolean adjacentok; /* False: at obj's spot only, True: nearby is allowed */
{
- struct monst *mtmp = (struct monst *) 0;
- struct monst *mtmp2 = (struct monst *) 0;
+ struct monst *mtmp, *mtmp2 = has_omonst(obj) ? get_mtraits(obj, TRUE) : 0;
- if (has_omonst(obj))
- mtmp2 = get_mtraits(obj, TRUE);
if (mtmp2) {
/* save_mtraits() validated mtmp2->mnum */
mtmp2->data = &mons[mtmp2->mnum];
mtmp = makemon(mtmp2->data, cc->x, cc->y,
(NO_MINVENT | MM_NOWAIT | MM_NOCOUNTBIRTH
| (adjacentok ? MM_ADJACENTOK : 0)));
- if (!mtmp)
- return mtmp;
+ if (!mtmp) {
+ /* mtmp2 is a copy of obj's object->oextra->omonst extension
+ and is not on the map or on any monst lists */
+ dealloc_monst(mtmp2);
+ return (struct monst *) 0;
+ }
/* heal the monster */
if (mtmp->mhpmax > mtmp2->mhpmax && is_rider(mtmp2->data))
ghost = find_mid(m_id, FM_FMON);
if (ghost && ghost->data == &mons[PM_GHOST]) {
if (canseemon(ghost))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s is suddenly drawn into its former body!",
#else
pline("%s\82Í\93Ë\91R\82à\82Æ\82Ì\91Ì\82É\88ø\82«\8d\9e\82Ü\82ê\82½\81I",
default:
/* if all else fails... */
pm_index = PM_STRAW_GOLEM;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
material = "";
#else
material = "\95¨\91Ì";
polyuse(obj, okind, (int) mons[pm_index].cwt);
if (mtmp && cansee(mtmp->mx, mtmp->my)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Some %sobjects meld, and %s arises from the pile!", material,
a_monnam(mtmp));
#else
else
delobj(obj);
if (cansee(mon->mx, mon->my))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline_The("figurine %sanimates!",
golem_xform ? "turns to flesh and " : "");
#else
(void) boxlock(obj, otmp);
if (obj_shudders(obj)) {
- boolean cover =
- ((obj == level.objects[u.ux][u.uy]) && u.uundetected
- && hides_under(youmonst.data));
+ boolean cover = ((obj == level.objects[u.ux][u.uy])
+ && u.uundetected
+ && hides_under(youmonst.data));
if (cansee(obj->ox, obj->oy))
learn_it = TRUE;
/* we don't want to force alive vs dead
determination for Schroedinger's Cat here,
so just make probing be inconclusive for it */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("aren't sure whether %s has %s or its corpse inside.",
the(xname(obj)),
/* unfortunately, we can't tell whether rndmonnam()
obj->cknown = 0;
} else {
struct obj *o;
+
/* view contents (not recursively) */
for (o = obj->cobj; o; o = o->nobj)
o->dknown = 1; /* "seen", even if blind */
} else {
if (cansee(ox, oy)) {
if (canspotmon(mtmp)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s is resurrected!",
upstart(noname_monnam(mtmp, ARTICLE_THE)));
#else
learn_it = TRUE;
(void) unturn_dead(&youmonst);
if (is_undead(youmonst.data)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_feel("frightened and %sstunned.",
Stunned ? "even more " : "");
#else
learn_it = TRUE;
unpunish();
}
- if (u.utrap) { /* escape web or bear trap */
- (void) openholdingtrap(&youmonst, &learn_it);
- } else {
+ /* invent is hit iff hero doesn't escape from a trap */
+ if (!u.utrap || !openholdingtrap(&youmonst, &learn_it)) {
struct obj *otmp;
+ boolean boxing = FALSE;
+
/* unlock carried boxes */
for (otmp = invent; otmp; otmp = otmp->nobj)
- if (Is_box(otmp))
+ if (Is_box(otmp)) {
(void) boxlock(otmp, obj);
+ boxing = TRUE;
+ }
+ if (boxing)
+ update_inventory(); /* in case any box->lknown has changed */
+
/* trigger previously escaped trapdoor */
(void) openfallingtrap(&youmonst, TRUE, &learn_it);
}
break;
case WAN_LOCKING:
case SPE_WIZARD_LOCK:
- if (!u.utrap) {
- (void) closeholdingtrap(&youmonst, &learn_it);
+ /* similar logic to opening; invent is hit iff no trap triggered */
+ if (u.utrap || !closeholdingtrap(&youmonst, &learn_it)) {
+ struct obj *otmp;
+ boolean boxing = FALSE;
+
+ /* lock carried boxes */
+ for (otmp = invent; otmp; otmp = otmp->nobj)
+ if (Is_box(otmp)) {
+ (void) boxlock(otmp, obj);
+ boxing = TRUE;
+ }
+ if (boxing)
+ update_inventory(); /* in case any box->lknown has changed */
}
break;
case WAN_DIGGING:
otmp->cknown = 1;
}
}
+ update_inventory();
learn_it = TRUE;
ustatusline();
break;
&& !Is_qstart(&u.uz)) {
int dmg;
/* similar to zap_dig() */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("A rock is dislodged from the %s and falls on your %s.",
ceiling(x, y), body_part(HEAD));
#else
/* locking transforms hole into trapdoor */
ttmp->ttyp = TRAPDOOR;
if (Blind || !ttmp->tseen) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Some %s swirls beneath you.",
is_ice(x, y) ? "frost" : "dust");
#else
case SPE_STONE_TO_FLESH:
if (e->engr_type == ENGRAVE) {
/* only affects things in stone */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline_The(Hallucination
? "floor runs like butter!"
: "edges on the floor get smoother.");
*/
pline("%s\82Í\89½\82©\82É\96½\92\86\82µ\82½\81D", str);
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s %s%s", The(str), vtense(str, "hit"),
mon_nam(mtmp), force);
#else
register const char *str;
register struct monst *mtmp;
{
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline(
"%s %s %s.", The(str), vtense(str, "miss"),
((cansee(bhitpos.x, bhitpos.y) || canspotmon(mtmp)) && flags.verbose)
struct obj **pobj; /* object tossed/used, set to NULL
* if object is destroyed */
{
- struct monst *mtmp;
+ struct monst *mtmp, *result = (struct monst *) 0;
struct obj *obj = *pobj;
uchar typ;
boolean shopdoor = FALSE, point_blank = TRUE;
if (weapon == FLASHED_LIGHT) {
tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam));
} else if (weapon == THROWN_TETHERED_WEAPON && obj) {
- tethered_weapon = TRUE;
- weapon = THROWN_WEAPON; /* simplify if's that follow below */
- tmp_at(DISP_TETHER, obj_to_glyph(obj, rn2_on_display_rng));
+ tethered_weapon = TRUE;
+ weapon = THROWN_WEAPON; /* simplify 'if's that follow below */
+ tmp_at(DISP_TETHER, obj_to_glyph(obj, rn2_on_display_rng));
} else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM)
tmp_at(DISP_FLASH, obj_to_glyph(obj, rn2_on_display_rng));
if (is_pick(obj) && inside_shop(x, y)
&& (mtmp = shkcatch(obj, x, y)) != 0) {
tmp_at(DISP_END, 0);
- return mtmp;
+ result = mtmp;
+ goto bhit_done;
}
typ = levl[bhitpos.x][bhitpos.y].typ;
- /* iron bars will block anything big enough */
- if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
- && typ == IRONBARS
- && hits_bars(pobj, x - ddx, y - ddy, bhitpos.x, bhitpos.y,
- point_blank ? 0 : !rn2(5), 1)) {
- /* caveat: obj might now be null... */
- obj = *pobj;
- bhitpos.x -= ddx;
- bhitpos.y -= ddy;
- break;
+ /* iron bars will block anything big enough and break some things */
+ if (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) {
+ if (typ == IRONBARS
+ && hits_bars(pobj, x - ddx, y - ddy, bhitpos.x, bhitpos.y,
+ point_blank ? 0 : !rn2(5), 1)) {
+ /* caveat: obj might now be null... */
+ obj = *pobj;
+ bhitpos.x -= ddx;
+ bhitpos.y -= ddy;
+ break;
+ } else if (obj->lamplit && !Blind) {
+ show_transient_light(obj, bhitpos.x, bhitpos.y);
+ }
}
if (weapon == ZAPPED_WAND && find_drawbridge(&x, &y)) {
if (is_pool(bhitpos.x, bhitpos.y) && !mtmp) {
in_skip = TRUE;
if (!Blind)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s%s.", Yname2(obj), otense(obj, "skip"),
skipcount ? " again" : "");
#else
if (range > 3) /* another bounce? */
skiprange(range, &skiprange_start, &skiprange_end);
} else if (mtmp && M_IN_WATER(mtmp->data)) {
- if ((!Blind && canseemon(mtmp)) || sensemon(mtmp))
-#if 0 /*JP*/
+ if (!Blind && canspotmon(mtmp))
+#if 0 /*JP:T*/
pline("%s %s over %s.", Yname2(obj), otense(obj, "pass"),
mon_nam(mtmp));
#else
pline("%s\82Í%s\82ð\94ò\82Ñ\89z\82¦\82½\81D", Yname2(obj),
mon_nam(mtmp));
#endif
+ mtmp = (struct monst *) 0;
}
}
- if (mtmp && !(in_skip && M_IN_WATER(mtmp->data))) {
+ /* if mtmp is a shade and missile passes harmlessly through it,
+ give message and skip it in order to keep going */
+ if (mtmp && (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
+ && shade_miss(&youmonst, mtmp, obj, TRUE, TRUE))
+ mtmp = (struct monst *) 0;
+
+ if (mtmp) {
notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
if (weapon == FLASHED_LIGHT) {
/* FLASHED_LIGHT hitting invisible monster should
(void) flash_hits_mon(mtmp, obj);
} else {
tmp_at(DISP_END, 0);
- return mtmp; /* caller will call flash_hits_mon */
+ result = mtmp; /* caller will call flash_hits_mon */
+ goto bhit_done;
}
} else if (weapon == INVIS_BEAM) {
/* Like FLASHED_LIGHT, INVIS_BEAM should continue
prepared for multiple hits so just get first one
that's either visible or could see its invisible
self. [No tmp_at() cleanup is needed here.] */
- if (!mtmp->minvis || perceives(mtmp->data))
- return mtmp;
+ if (!mtmp->minvis || perceives(mtmp->data)) {
+ result = mtmp;
+ goto bhit_done;
+ }
} else if (weapon != ZAPPED_WAND) {
/* THROWN_WEAPON, KICKED_WEAPON */
if (cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp))
map_invisible(bhitpos.x, bhitpos.y);
- return mtmp;
+ result = mtmp;
+ goto bhit_done;
} else {
/* ZAPPED_WAND */
(*fhitm)(mtmp, obj);
|| ship_object(obj, bhitpos.x, bhitpos.y,
costly_spot(bhitpos.x, bhitpos.y)))) {
tmp_at(DISP_END, 0);
- return (struct monst *) 0;
+ goto bhit_done; /* result == (struct monst *) 0 */
}
}
if (weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) {
if ((bobj = sobj_at(BOULDER, x, y)) != 0) {
if (cansee(x, y))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s hits %s.", The(distant_name(obj, xname)),
an(xname(bobj)));
#else
if (!test_move(x - ddx, y - ddy, ddx, ddy, TEST_MOVE)) {
/* nb: it didn't hit anything directly */
if (cansee(x, y))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s jerks to an abrupt halt.",
The(distant_name(obj, xname))); /* lame */
#else
*/
pay_for_damage("\94j\89ó\82·\82é", FALSE);
- return (struct monst *) 0;
+ bhit_done:
+ if (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
+ transient_light_cleanup();
+
+ return result;
}
/* process thrown boomerang, which travels a curving path...
if (!u.ustuck)
u.uswallow = 0;
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s rips into %s%s", The(fltxt), mon_nam(u.ustuck),
exclam(tmp));
#else
break;
if (type >= 0)
mon->mstrategy &= ~STRAT_WAITMASK;
- buzzmonst:
+ buzzmonst:
notonhead = (mon->mx != bhitpos.x || mon->my != bhitpos.y);
if (zap_hit(find_mac(mon), spell_type)) {
if (mon_reflects(mon, (char *) 0)) {
if (cansee(mon->mx, mon->my)) {
hit(fltxt, mon, exclam(0));
shieldeff(mon->mx, mon->my);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
(void) mon_reflects(mon,
"But it reflects from %s %s!");
#else
hit(fltxt, mon, ".");
*/
hit(fltxt, mon, "\81D");
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s absorbs the deadly %s!", Monnam(mon),
type == ZT_BREATH(ZT_DEATH) ? "blast"
: "ray");
} else {
/* some armor was destroyed; no damage done */
if (canseemon(mon))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s is disintegrated!",
s_suffix(Monnam(mon)),
distant_name(otmp, xname));
pline("%s\82Í\82 \82È\82½\82É\96½\92\86\82µ\82½\81I", fltxt);
if (Reflecting) {
if (!Blind) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
(void) ureflects("But %s reflects from your %s!",
"it");
#else
uchar rmn;
boolean fireball;
- make_bounce:
+ make_bounce:
bchance = (levl[sx][sy].typ == STONE) ? 10
: (In_mines(&u.uz) && IS_WALL(levl[sx][sy].typ)) ? 20
: 75;
if (type == ZT_SPELL(ZT_FIRE))
explode(sx, sy, type, d(12, 6), 0, EXPL_FIERY);
if (shopdamage)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pay_for_damage(abstype == ZT_FIRE
? "burn away"
: abstype == ZT_COLD
if (is_ice(x, y)) {
melt_ice(x, y, (char *) 0);
} else if (is_pool(x, y)) {
-/*JP
- const char *msgtxt = "You hear hissing gas.";
-*/
- const char *msgtxt = "\82µ\82ã\81[\82Á\82Æ\82¢\82¤\83K\83X\82Ì\89¹\82ð\95·\82¢\82½\81D";
+#if 0 /*JP*/
+ const char *msgtxt = (!Deaf)
+ ? "You hear hissing gas." /* Deaf-aware */
+ : (type >= 0)
+ ? "That seemed remarkably uneventful."
+ : (const char *) 0;
+#else
+ const char *msgtxt = (!Deaf)
+ ? "\82µ\82ã\81[\82Á\82Æ\82¢\82¤\83K\83X\82Ì\89¹\82ð\95·\82¢\82½\81D" /* Deaf-aware */
+ : (type >= 0)
+ ? "\82±\82ê\82Í\8bÁ\82\82Ù\82Ç\82È\82ñ\82Å\82à\82È\82³\82»\82¤\82¾\81D"
+ : (const char *) 0;
+#endif
if (lev->typ != POOL) { /* MOAT or DRAWBRIDGE_UP */
if (see_it)
*/
msgtxt = "\90\85\82ª\8fö\94\82µ\82½\81D";
}
- Norep("%s", msgtxt);
+ if (msgtxt)
+ Norep("%s", msgtxt);
if (lev->typ == ROOM)
newsym(x, y);
} else if (IS_FOUNTAIN(lev->typ)) {
/* set up zap text for possible door feedback; for exploding wand, we
want "the blast" rather than "your blast" even if hero caused it */
yourzap = (type >= 0 && !exploding_wand_typ);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
zapverb = "blast"; /* breath attack or wand explosion */
#else
zapverb = "\8fÕ\8c\82"; /* breath attack or wand explosion */
#endif
if (!exploding_wand_typ) {
if (abs(type) < ZT_SPELL(0))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
zapverb = "bolt"; /* wand zap */
#else
zapverb = "\8cõ\90ü"; /* wand zap */
(except on rogue level) */
newsym(x, y);
if (see_it)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s reveals a secret door.",
yourzap ? "Your" : "The", zapverb);
#else
hear_txt = "\83s\83L\83s\83L\82Æ\82¢\82¤\89¹\82ð\95·\82¢\82½\81D";
break;
default:
- def_case:
+ def_case:
if (exploding_wand_typ > 0) {
/* Magical explosion from misc exploding wand */
if (exploding_wand_typ == WAN_STRIKING) {
*/
pline_The("\94à\82Í\96³\8f\9d\82¾\81D");
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline_The("door absorbs %s %s!", yourzap ? "your" : "the",
zapverb);
#else
if (!cnt)
return;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
mult = (cnt == 1L)
? ((quan == 1L) ? "Your" /* 1 of 1 */
: "One of your") /* 1 of N */
if (dmg) {
if (xresist) {
/*JP
- You("aren't hurt!");
+ You("aren't hurt!");
*/
- You("\8f\9d\82Â\82©\82È\82¢\81I");
+ You("\8f\9d\82Â\82©\82È\82¢\81I");
} else {
const char *how = destroy_strings[dindx][2];
boolean one = (cnt == 1L);
if (dmgtyp == AD_FIRE && osym == FOOD_CLASS)
/*JP
- how = "exploding glob of slime";
+ how = "exploding glob of slime";
*/
- how = "\83X\83\89\83C\83\80\82Ì\82Ë\82Î\82Ë\82Î\82Ì\94\9a\94\82Å";
+ how = "\83X\83\89\83C\83\80\82Ì\82Ë\82Î\82Ë\82Î\82Ì\94\9a\94\82Å";
if (physical_damage)
dmg = Maybe_Half_Phys(dmg);
losehp(dmg, one ? how : (const char *) makeplural(how),
if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
skip++;
if (vis)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s glows a strange %s, but remains intact.",
The(distant_name(obj, xname)), hcolor("dark red"));
#else
if (!cnt)
continue;
if (vis)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s%s %s!",
(cnt == obj->quan) ? "" : (cnt > 1L) ? "Some of "
: "One of ",
You("may wish for an object.");
*/
You("\96]\82Ý\82Ì\82à\82Ì\82ð\8eè\82É\93ü\82ê\82ç\82ê\82é\81D");
-retry:
+ retry:
/*JP
Strcpy(promptbuf, "For what do you wish");
*/
buf[0] = '\0';
} else if (!strcmpi(buf, "help")) {
wishcmdassist(MAXWISHTRY - tries);
+ buf[0] = '\0'; /* for EDIT_GETLIN */
goto retry;
}
/*