1 /* NetHack 3.6 zap.c $NHDT-Date: 1573688696 2019/11/13 23:44:56 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.316 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2013. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
9 /* JNetHack may be freely redistributed. See license for details. */
13 /* Disintegration rays have special treatment; corpses are never left.
14 * But the routine which calculates the damage is separate from the routine
15 * which kills the monster. The damage routine returns this cookie to
16 * indicate that the monster should be disintegrated.
18 #define MAGIC_COOKIE 1000
20 static NEARDATA boolean obj_zapped;
21 static NEARDATA int poly_zapped;
23 extern boolean notonhead; /* for long worms */
25 /* kludge to use mondied instead of killed */
26 extern boolean m_using;
28 STATIC_DCL void FDECL(polyuse, (struct obj *, int, int));
29 STATIC_DCL void FDECL(create_polymon, (struct obj *, int));
30 STATIC_DCL int FDECL(stone_to_flesh_obj, (struct obj *));
31 STATIC_DCL boolean FDECL(zap_updown, (struct obj *));
32 STATIC_DCL void FDECL(zhitu, (int, int, const char *, XCHAR_P, XCHAR_P));
33 STATIC_DCL void FDECL(revive_egg, (struct obj *));
34 STATIC_DCL boolean FDECL(zap_steed, (struct obj *));
35 STATIC_DCL void FDECL(skiprange, (int, int *, int *));
36 STATIC_DCL int FDECL(zap_hit, (int, int));
37 STATIC_OVL void FDECL(disintegrate_mon, (struct monst *, int, const char *));
38 STATIC_DCL void FDECL(backfire, (struct obj *));
39 STATIC_DCL int FDECL(spell_hit_bonus, (int));
40 STATIC_DCL void FDECL(destroy_one_item, (struct obj *, int, int));
41 STATIC_DCL void FDECL(wishcmdassist, (int));
43 #define ZT_MAGIC_MISSILE (AD_MAGM - 1)
44 #define ZT_FIRE (AD_FIRE - 1)
45 #define ZT_COLD (AD_COLD - 1)
46 #define ZT_SLEEP (AD_SLEE - 1)
47 #define ZT_DEATH (AD_DISN - 1) /* or disintegration */
48 #define ZT_LIGHTNING (AD_ELEC - 1)
49 #define ZT_POISON_GAS (AD_DRST - 1)
50 #define ZT_ACID (AD_ACID - 1)
51 /* 8 and 9 are currently unassigned */
53 #define ZT_WAND(x) (x)
54 #define ZT_SPELL(x) (10 + (x))
55 #define ZT_BREATH(x) (20 + (x))
57 #define is_hero_spell(type) ((type) >= 10 && (type) < 20)
59 #define M_IN_WATER(ptr) \
60 ((ptr)->mlet == S_EEL || amphibious(ptr) || is_swimmer(ptr))
62 STATIC_VAR const char are_blinded_by_the_flash[] =
64 "are blinded by the flash!";
66 "
\82Ü
\82Î
\82ä
\82¢
\8cõ
\82Å
\96Ú
\82ª
\8c©
\82¦
\82È
\82
\82È
\82Á
\82½
\81I";
68 const char *const flash_types[] = /* also used in buzzmu(mcastu.c) */
71 "magic missile", /* Wands must be 0-9 */
72 "bolt of fire", "bolt of cold", "sleep ray", "death ray",
73 "bolt of lightning", "", "", "", "",
75 "
\96\82\96@
\82Ì
\96î", /* Wands must be 0-9 */
80 "
\88î
\8dÈ
\82Ì
\91M
\8cõ",
88 "magic missile", /* Spell equivalents must be 10-19 */
89 "fireball", "cone of cold", "sleep ray", "finger of death",
90 "bolt of lightning", /* there is no spell, used for retribution */
93 "
\96\82\96@
\82Ì
\96î", /* Spell equivalents must be 10-19 */
98 "
\88î
\8dÈ
\82Ì
\91M
\8cõ", /* There is no spell, used for retribution */
106 "blast of missiles", /* Dragon breath equivalents 20-29*/
107 "blast of fire", "blast of frost", "blast of sleep gas",
108 "blast of disintegration", "blast of lightning",
109 "blast of poison gas", "blast of acid", "", ""
111 "
\96\82\96@
\82Ì
\96î
\82Ì
\91§", /* Dragon breath equivalents 20-29*/
114 "
\90\87\96°
\83K
\83X
\82Ì
\91§",
117 "
\93Å
\83K
\83X
\82Ì
\91§",
125 * Recognizing unseen wands by zapping: in 3.4.3 and earlier, zapping
126 * most wand types while blind would add that type to the discoveries
127 * list even if it had never been seen (ie, picked up while blinded
128 * and shown in inventory as simply "a wand"). This behavior has been
129 * changed; now such wands won't be discovered. But if the type is
130 * already discovered, then the individual wand whose effect was just
131 * observed will be flagged as if seen. [You already know wands of
132 * striking; you zap "a wand" and observe striking effect (presumably
133 * by sound or touch); it'll become shown in inventory as "a wand of
136 * Unfortunately, the new behavior isn't really correct either. There
137 * should be an `eknown' bit for "effect known" added for wands (and
138 * for potions since quaffing one of a stack is similar) so that the
139 * particular wand which has been zapped would have its type become
140 * known (it would change from "a wand" to "a wand of striking", for
141 * example) without the type becoming discovered or other unknown wands
142 * of that type showing additional information. When blindness ends,
143 * all objects in inventory with the eknown bit set would be discovered
144 * and other items of the same type would become known as such.
147 /* wand discovery gets special handling when hero is blinded */
152 /* For a wand (or wand-like tool) zapped by the player, if the
153 effect was observable (determined by caller; usually seen, but
154 possibly heard or felt if the hero is blinded) then discover the
155 object type provided that the object itself is known (as more
156 than just "a wand"). If object type is already discovered and
157 we observed the effect, mark the individual wand as having been
158 seen. Suppress spells (which use fake spellbook object for `obj')
159 so that casting a spell won't re-discover its forgotten book. */
160 if (obj->oclass != SPBOOK_CLASS) {
161 /* if type already discovered, treat this item has having been seen
162 even if hero is currently blinded (skips redundant makeknown) */
163 if (objects[obj->otyp].oc_name_known) {
164 obj->dknown = 1; /* will usually be set already */
166 /* otherwise discover it if item itself has been or can be seen */
168 /* in case it was picked up while blind and then zapped without
169 examining inventory after regaining sight (bypassing xname) */
172 /* make the discovery iff we know what we're manipulating */
174 makeknown(obj->otyp);
180 /* Routines for IMMEDIATE wands and spells. */
181 /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */
187 boolean wake = TRUE; /* Most 'zaps' should wake monster */
188 boolean reveal_invis = FALSE, learn_it = FALSE;
189 boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart;
190 boolean skilled_spell, helpful_gesture = FALSE;
191 int dmg, otyp = otmp->otyp;
193 const char *zap_type_text = "spell";
195 const char *zap_type_text = "
\96\82\96@";
197 boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC
198 && M_AP_TYPE(mtmp) != M_AP_NOTHING);
200 if (u.uswallow && mtmp == u.ustuck)
201 reveal_invis = FALSE;
203 notonhead = (mtmp->mx != bhitpos.x || mtmp->my != bhitpos.y);
204 skilled_spell = (otmp && otmp->oclass == SPBOOK_CLASS && otmp->blessed);
209 zap_type_text = "wand";
211 zap_type_text = "
\8fñ";
217 if (resists_magm(mtmp)) { /* match effect on player */
218 shieldeff(mtmp->mx, mtmp->my);
222 pline("
\83{
\83C
\83\93\81I");
223 break; /* skip makeknown */
224 } else if (u.uswallow || rnd(20) < 10 + find_mac(mtmp)) {
228 if (otyp == SPE_FORCE_BOLT)
229 dmg = spell_damage_bonus(dmg);
230 hit(zap_type_text, mtmp, exclam(dmg));
231 (void) resist(mtmp, otmp->oclass, dmg, TELL);
233 miss(zap_type_text, mtmp);
236 case WAN_SLOW_MONSTER:
237 case SPE_SLOW_MONSTER:
238 if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
241 mon_adjust_speed(mtmp, -1, otmp);
242 m_dowear(mtmp, FALSE); /* might want speed boots */
243 if (u.uswallow && (mtmp == u.ustuck) && is_whirly(mtmp->data)) {
245 You("disrupt %s!", mon_nam(mtmp));
247 You("%s
\82ð
\83o
\83\89\83o
\83\89\82É
\82µ
\82½
\81I", mon_nam(mtmp));
249 pline("A huge hole opens up...");
251 pline("
\92E
\8fo
\82Å
\82«
\82»
\82¤
\82È
\8c\8a\82ª
\8aJ
\82¢
\82½
\81D
\81D
\81D");
252 expels(mtmp, mtmp->data, TRUE);
256 case WAN_SPEED_MONSTER:
257 if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
260 mon_adjust_speed(mtmp, 1, otmp);
261 m_dowear(mtmp, FALSE); /* might want speed boots */
264 helpful_gesture = TRUE;
266 case WAN_UNDEAD_TURNING:
267 case SPE_TURN_UNDEAD:
269 if (unturn_dead(mtmp))
271 if (is_undead(mtmp->data) || is_vampshifter(mtmp)) {
277 if (otyp == SPE_TURN_UNDEAD)
278 dmg = spell_damage_bonus(dmg);
279 context.bypasses = TRUE; /* for make_corpse() */
280 if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) {
281 if (!DEADMONSTER(mtmp))
282 monflee(mtmp, 0, FALSE, TRUE);
289 if (mtmp->data == &mons[PM_LONG_WORM] && has_mcorpsenm(mtmp)) {
290 /* if a long worm has mcorpsenm set, it was polymophed by
291 the current zap and shouldn't be affected if hit again */
293 } else if (resists_magm(mtmp)) {
294 /* magic resistance protects from polymorph traps, so make
295 it guard against involuntary polymorph attacks too... */
296 shieldeff(mtmp->mx, mtmp->my);
297 } else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
298 boolean polyspot = (otyp != POT_POLYMORPH),
299 give_msg = (!Hallucination
301 || (u.uswallow && mtmp == u.ustuck)));
303 /* dropped inventory (due to death by system shock,
304 or loss of wielded weapon and/or worn armor due to
305 limitations of new shape) won't be hit by this zap */
307 for (obj = mtmp->minvent; obj; obj = obj->nobj)
310 /* natural shapechangers aren't affected by system shock
311 (unless protection from shapechangers is interfering
312 with their metabolism...) */
313 if (mtmp->cham == NON_PM && !rn2(25)) {
314 if (canseemon(mtmp)) {
316 pline("%s shudders!", Monnam(mtmp));
318 pline("%s
\82Í
\90g
\90k
\82¢
\82µ
\82½
\81I", Monnam(mtmp));
321 /* context.bypasses = TRUE; ## for make_corpse() */
322 /* no corpse after system shock */
323 xkilled(mtmp, XKILL_GIVEMSG | XKILL_NOCORPSE);
324 } else if (newcham(mtmp, (struct permonst *) 0,
325 polyspot, give_msg) != 0
326 /* if shapechange failed because there aren't
327 enough eligible candidates (most likely for
328 vampshifter), try reverting to original form */
329 || (mtmp->cham >= LOW_PM
330 && newcham(mtmp, &mons[mtmp->cham],
331 polyspot, give_msg) != 0)) {
332 if (give_msg && (canspotmon(mtmp)
333 || (u.uswallow && mtmp == u.ustuck)))
337 /* do this even if polymorphed failed (otherwise using
338 flags.mon_polycontrol prompting to force mtmp to remain
339 'long worm' would prompt again if zap hit another segment) */
340 if (!DEADMONSTER(mtmp) && mtmp->data == &mons[PM_LONG_WORM]) {
341 if (!has_mcorpsenm(mtmp))
343 /* flag to indicate that mtmp became a long worm
344 on current zap, so further hits (on mtmp's new
345 tail) don't do further transforms */
346 MCORPSENM(mtmp) = PM_LONG_WORM;
347 /* flag to indicate that cleanup is needed; object
348 bypass cleanup also clears mon->mextra->mcorpsenm
349 for all long worms on the level */
350 context.bypasses = TRUE;
354 case WAN_CANCELLATION:
355 case SPE_CANCELLATION:
358 (void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE);
360 case WAN_TELEPORTATION:
361 case SPE_TELEPORT_AWAY:
364 reveal_invis = !u_teleport_mon(mtmp, TRUE);
366 case WAN_MAKE_INVISIBLE: {
367 int oldinvis = mtmp->minvis;
372 /* format monster's name before altering its visibility */
373 Strcpy(nambuf, Monnam(mtmp));
374 mon_set_minvis(mtmp);
375 if (!oldinvis && knowninvisible(mtmp)) {
377 pline("%s turns transparent!", nambuf);
379 pline("%s
\82Í
\93§
\96¾
\82É
\82È
\82Á
\82½
\81I", nambuf);
386 case SPE_WIZARD_LOCK:
387 wake = closeholdingtrap(mtmp, &learn_it);
397 wake = FALSE; /* don't want immediate counterattack */
398 if (u.uswallow && mtmp == u.ustuck) {
399 if (is_animal(mtmp->data)) {
402 You_feel("a sudden rush of air!");
404 You("
\93Ë
\91R
\8c\83\82µ
\82¢
\8bó
\8bC
\82Ì
\97¬
\82ê
\82ð
\8a´
\82¶
\82½
\81I");
407 pline("%s opens its mouth!", Monnam(mtmp));
409 pline("%s
\82Í
\8cû
\82ð
\8aJ
\82¢
\82½
\81I", Monnam(mtmp));
411 expels(mtmp, mtmp->data, TRUE);
412 /* zap which hits steed will only release saddle if it
413 doesn't hit a holding or falling trap; playability
414 here overrides the more logical target ordering */
415 } else if (openholdingtrap(mtmp, &learn_it)) {
417 } else if (openfallingtrap(mtmp, TRUE, &learn_it)) {
418 /* mtmp might now be on the migrating monsters list */
420 } else if ((obj = which_armor(mtmp, W_SADDLE)) != 0) {
424 Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)),
425 distant_name(obj, xname));
427 Sprintf(buf, "%s
\82Ì%s", Monnam(mtmp),
428 distant_name(obj, xname));
430 if (cansee(mtmp->mx, mtmp->my)) {
431 if (!canspotmon(mtmp))
432 Strcpy(buf, An(distant_name(obj, xname)));
434 pline("%s falls to the %s.", buf,
435 surface(mtmp->mx, mtmp->my));
437 pline("%s
\82Í%s
\82É
\97\8e\82¿
\82½
\81D", buf,
438 surface(mtmp->mx, mtmp->my));
440 } else if (canspotmon(mtmp)) {
442 pline("%s falls off.", buf);
444 pline("%s
\82ª
\97\8e\82¿
\82½
\81D", buf);
446 obj_extract_self(obj);
447 mdrop_obj(mtmp, obj, FALSE);
451 case SPE_EXTRA_HEALING:
453 if (mtmp->data != &mons[PM_PESTILENCE]) {
454 wake = FALSE; /* wakeup() makes the target angry */
455 mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4);
456 if (mtmp->mhp > mtmp->mhpmax)
457 mtmp->mhp = mtmp->mhpmax;
458 /* plain healing must be blessed to cure blindness; extra
459 healing only needs to not be cursed, so spell always cures
460 [potions quaffed by monsters behave slightly differently;
461 we use the rules for the hero here...] */
462 if (skilled_spell || otyp == SPE_EXTRA_HEALING)
463 mcureblindness(mtmp, canseemon(mtmp));
464 if (canseemon(mtmp)) {
465 if (disguised_mimic) {
466 if (is_obj_mappear(mtmp,STRANGE_OBJECT)) {
467 /* it can do better now */
469 newsym(mtmp->mx, mtmp->my);
471 mimic_hit_msg(mtmp, otyp);
474 pline("%s looks%s better.", Monnam(mtmp),
475 otyp == SPE_EXTRA_HEALING ? " much" : "");
477 pline("%s
\82Í%s
\8c³
\8bC
\82É
\82È
\82Á
\82½
\82æ
\82¤
\82¾
\81D", Monnam(mtmp),
478 otyp == SPE_EXTRA_HEALING ? "
\82Æ
\82Ä
\82à" : "" );
481 if (mtmp->mtame || mtmp->mpeaceful) {
482 adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type));
484 } else { /* Pestilence */
485 /* Pestilence will always resist; damage is half of 3d{4,8} */
486 (void) resist(mtmp, otmp->oclass,
487 d(3, otyp == SPE_EXTRA_HEALING ? 8 : 4), TELL);
490 case WAN_LIGHT: /* (broken wand) */
491 if (flash_hits_mon(mtmp, otmp)) {
496 case WAN_SLEEP: /* (broken wand) */
497 /* [wakeup() doesn't rouse victims of temporary sleep,
498 so it's okay to leave `wake' set to TRUE here] */
500 if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS))
505 case SPE_STONE_TO_FLESH:
506 if (monsndx(mtmp->data) == PM_STONE_GOLEM) {
507 char *name = Monnam(mtmp);
509 /* turn into flesh golem */
510 if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE, FALSE)) {
513 pline("%s turns to flesh!", name);
515 pline("%s
\82Ì
\90Î
\89»
\82ª
\89ð
\82¯
\82½
\81I", name);
519 pline("%s looks rather fleshy for a moment.", name);
521 pline("%s
\82Í
\88ê
\8fu
\90Î
\89»
\82ª
\89ð
\82¯
\82½
\81D", name);
529 dmg = monhp_per_lvl(mtmp);
532 if (otyp == SPE_DRAIN_LIFE)
533 dmg = spell_damage_bonus(dmg);
534 if (resists_drli(mtmp)) {
535 shieldeff(mtmp->mx, mtmp->my);
536 } else if (!resist(mtmp, otmp->oclass, dmg, NOTELL)
537 && !DEADMONSTER(mtmp)) {
540 /* die if already level 0, regardless of hit points */
541 if (DEADMONSTER(mtmp) || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) {
547 pline("%s suddenly seems weaker!", Monnam(mtmp));
549 pline("%s
\82Í
\82Æ
\82Â
\82º
\82ñ
\8eã
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I", Monnam(mtmp));
557 impossible("What an interesting effect (%d)", otyp);
561 if (!DEADMONSTER(mtmp)) {
562 wakeup(mtmp, helpful_gesture ? FALSE : TRUE);
564 if (mtmp->isshk && !*u.ushops)
566 } else if (M_AP_TYPE(mtmp))
567 seemimic(mtmp); /* might unblock if mimicing a boulder/door */
569 /* note: bhitpos won't be set if swallowed, but that's okay since
570 * reveal_invis will be false. We can't use mtmp->mx, my since it
571 * might be an invisible worm hit on the tail.
574 if (!DEADMONSTER(mtmp) && cansee(bhitpos.x, bhitpos.y)
575 && !canspotmon(mtmp))
576 map_invisible(bhitpos.x, bhitpos.y);
578 /* if effect was observable then discover the wand type provided
579 that the wand itself has been seen */
593 return; /* don't show minvent for long worm tail */
596 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
597 otmp->dknown = 1; /* treat as "seen" */
598 if (Is_container(otmp) || otmp->otyp == STATUE) {
600 if (!SchroedingersBox(otmp))
604 (void) display_minventory(mtmp, MINV_ALL | MINV_NOLET | PICK_NONE,
608 pline("%s is not carrying anything%s.", noit_Monnam(mtmp),
609 (u.uswallow && mtmp == u.ustuck) ? " besides you" : "");
611 pline("%s
\82Í%s
\89½
\82à
\8e\9d\82Á
\82Ä
\82¢
\82È
\82¢
\81D", noit_Monnam(mtmp),
612 (u.uswallow && mtmp == u.ustuck) ? "
\82 \82È
\82½
\88È
\8aO
\82É" : "");
618 * Return the object's physical location. This only makes sense for
619 * objects that are currently on the level (i.e. migrating objects
620 * are nowhere). By default, only things that can be seen (in hero's
621 * inventory, monster's inventory, or on the ground) are reported.
622 * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get
623 * the location of buried and contained objects. Note that if an
624 * object is carried by a monster, its reported position may change
625 * from turn to turn. This function returns FALSE if the position
626 * is not available or subject to the constraints above.
629 get_obj_location(obj, xp, yp, locflags)
634 switch (obj->where) {
644 if (obj->ocarry->mx) {
645 *xp = obj->ocarry->mx;
646 *yp = obj->ocarry->my;
649 break; /* !mx => migrating monster */
651 if (locflags & BURIED_TOO) {
658 if (locflags & CONTAINED_TOO)
659 return get_obj_location(obj->ocontainer, xp, yp, locflags);
667 get_mon_location(mon, xp, yp, locflags)
670 int locflags; /* non-zero means get location even if monster is buried */
672 if (mon == &youmonst) {
676 } else if (mon->mx > 0 && (!mon->mburied || locflags)) {
680 } else { /* migrating or buried */
686 /* used by revive() and animate_statue() */
688 montraits(obj, cc, adjacentok)
691 boolean adjacentok; /* False: at obj's spot only, True: nearby is allowed */
693 struct monst *mtmp, *mtmp2 = has_omonst(obj) ? get_mtraits(obj, TRUE) : 0;
696 /* save_mtraits() validated mtmp2->mnum */
697 mtmp2->data = &mons[mtmp2->mnum];
698 if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data))
699 return (struct monst *) 0;
700 mtmp = makemon(mtmp2->data, cc->x, cc->y,
701 (NO_MINVENT | MM_NOWAIT | MM_NOCOUNTBIRTH
702 | (adjacentok ? MM_ADJACENTOK : 0)));
704 /* mtmp2 is a copy of obj's object->oextra->omonst extension
705 and is not on the map or on any monst lists */
706 dealloc_monst(mtmp2);
707 return (struct monst *) 0;
710 /* heal the monster */
711 if (mtmp->mhpmax > mtmp2->mhpmax && is_rider(mtmp2->data))
712 mtmp2->mhpmax = mtmp->mhpmax;
713 mtmp2->mhp = mtmp2->mhpmax;
714 /* Get these ones from mtmp */
715 mtmp2->minvent = mtmp->minvent; /*redundant*/
716 /* monster ID is available if the monster died in the current
717 game, but will be zero if the corpse was in a bones level
718 (we cleared it when loading bones) */
720 mtmp2->m_id = mtmp->m_id;
721 /* might be bringing quest leader back to life */
722 if (quest_status.leader_is_dead
723 /* leader_is_dead implies leader_m_id is valid */
724 && mtmp2->m_id == quest_status.leader_m_id)
725 quest_status.leader_is_dead = FALSE;
727 mtmp2->mx = mtmp->mx;
728 mtmp2->my = mtmp->my;
729 mtmp2->mux = mtmp->mux;
730 mtmp2->muy = mtmp->muy;
731 mtmp2->mw = mtmp->mw;
732 mtmp2->wormno = mtmp->wormno;
733 mtmp2->misc_worn_check = mtmp->misc_worn_check;
734 mtmp2->weapon_check = mtmp->weapon_check;
735 mtmp2->mtrapseen = mtmp->mtrapseen;
736 mtmp2->mflee = mtmp->mflee;
737 mtmp2->mburied = mtmp->mburied;
738 mtmp2->mundetected = mtmp->mundetected;
739 mtmp2->mfleetim = mtmp->mfleetim;
740 mtmp2->mlstmv = mtmp->mlstmv;
741 mtmp2->m_ap_type = mtmp->m_ap_type;
742 /* set these ones explicitly */
748 mtmp2->msleeping = 0;
751 /* most cancelled monsters return to normal,
752 but some need to stay cancelled */
753 if (!dmgtype(mtmp2->data, AD_SEDU)
754 && (!SYSOPT_SEDUCE || !dmgtype(mtmp2->data, AD_SSEX)))
756 mtmp2->mcansee = 1; /* set like in makemon */
760 /* when traits are for a shopeekper, dummy monster 'mtmp' won't
761 have necessary eshk data for replmon() -> replshk() */
764 *ESHK(mtmp) = *ESHK(mtmp2);
765 if (ESHK(mtmp2)->bill_p != 0
766 && ESHK(mtmp2)->bill_p != (struct bill_x *) -1000)
767 ESHK(mtmp)->bill_p = &(ESHK(mtmp)->bill[0]);
770 replmon(mtmp, mtmp2);
771 newsym(mtmp2->mx, mtmp2->my); /* Might now be invisible */
773 /* in case Protection_from_shape_changers is different
774 now than it was when the traits were stored */
781 * get_container_location() returns the following information
782 * about the outermost container:
783 * loc argument gets set to:
784 * OBJ_INVENT if in hero's inventory; return 0.
785 * OBJ_FLOOR if on the floor; return 0.
786 * OBJ_BURIED if buried; return 0.
787 * OBJ_MINVENT if in monster's inventory; return monster.
788 * container_nesting is updated with the nesting depth of the containers
792 get_container_location(obj, loc, container_nesting)
795 int *container_nesting;
800 if (container_nesting)
801 *container_nesting = 0;
802 while (obj && obj->where == OBJ_CONTAINED) {
803 if (container_nesting)
804 *container_nesting += 1;
805 obj = obj->ocontainer;
808 *loc = obj->where; /* outermost container's location */
809 if (obj->where == OBJ_MINVENT)
812 return (struct monst *) 0;
816 * Attempt to revive the given corpse, return the revived monster if
817 * successful. Note: this does NOT use up the corpse if it fails.
818 * If corpse->quan is more than 1, only one corpse will be affected
819 * and only one monster will be resurrected.
822 revive(corpse, by_hero)
826 struct monst *mtmp = 0;
827 struct permonst *mptr;
828 struct obj *container;
832 int montype, container_nesting = 0;
834 if (corpse->otyp != CORPSE) {
835 impossible("Attempting to revive %s?", xname(corpse));
836 return (struct monst *) 0;
840 if (corpse->where != OBJ_CONTAINED) {
841 /* only for invent, minvent, or floor */
843 (void) get_obj_location(corpse, &x, &y, 0);
845 /* deal with corpses in [possibly nested] containers */
846 struct monst *carrier;
847 int holder = OBJ_FREE;
849 container = corpse->ocontainer;
851 get_container_location(container, &holder, &container_nesting);
854 x = carrier->mx, y = carrier->my;
860 (void) get_obj_location(corpse, &x, &y, CONTAINED_TOO);
863 break; /* x,y are 0 */
867 /* Rules for revival from containers:
868 * - the container cannot be locked
869 * - the container cannot be heavily nested (>2 is arbitrary)
870 * - the container cannot be a statue or bag of holding
871 * (except in very rare cases for the latter)
873 || (container && (container->olocked || container_nesting > 2
874 || container->otyp == STATUE
875 || (container->otyp == BAG_OF_HOLDING && rn2(40)))))
876 return (struct monst *) 0;
878 /* record the object's location now that we're sure where it is */
879 corpse->ox = x, corpse->oy = y;
881 /* prepare for the monster */
882 montype = corpse->corpsenm;
883 mptr = &mons[montype];
884 /* [should probably handle recorporealization first; if corpse and
885 ghost are at same location, revived creature shouldn't be bumped
886 to an adjacent spot by ghost which joins with it] */
888 if (enexto(&xy, x, y, mptr))
892 if ((mons[montype].mlet == S_EEL && !IS_POOL(levl[x][y].typ))
893 || (mons[montype].mlet == S_TROLL
894 && uwep && uwep->oartifact == ART_TROLLSBANE)) {
895 if (by_hero && cansee(x, y))
897 pline("%s twitches feebly.",
899 pline("%s
\82Í
\82í
\82¸
\82©
\82Éáz
\9d¹
\82µ
\82½
\81D",
900 upstart(corpse_xname(corpse, (const char *) 0, CXN_PFX_THE)));
901 return (struct monst *) 0;
904 if (cant_revive(&montype, TRUE, corpse)) {
905 /* make a zombie or doppelganger instead */
906 /* note: montype has changed; mptr keeps old value for newcham() */
907 mtmp = makemon(&mons[montype], x, y, NO_MINVENT | MM_NOWAIT);
909 /* skip ghost handling */
910 if (has_omid(corpse))
912 if (has_omonst(corpse))
914 if (mtmp->cham == PM_DOPPELGANGER) {
915 /* change shape to match the corpse */
916 (void) newcham(mtmp, mptr, FALSE, FALSE);
917 } else if (mtmp->data->mlet == S_ZOMBIE) {
918 mtmp->mhp = mtmp->mhpmax = 100;
919 mon_adjust_speed(mtmp, 2, (struct obj *) 0); /* MFAST */
922 } else if (has_omonst(corpse)) {
923 /* use saved traits */
925 mtmp = montraits(corpse, &xy, FALSE);
926 if (mtmp && mtmp->mtame && !mtmp->isminion)
927 wary_dog(mtmp, TRUE);
929 /* make a new monster */
930 mtmp = makemon(mptr, x, y, NO_MINVENT | MM_NOWAIT | MM_NOCOUNTBIRTH);
933 return (struct monst *) 0;
935 /* hiders shouldn't already be re-hidden when they revive */
936 if (mtmp->mundetected) {
937 mtmp->mundetected = 0;
938 newsym(mtmp->mx, mtmp->my);
943 one_of = (corpse->quan > 1L);
945 corpse = splitobj(corpse, 1L);
947 /* if this is caused by the hero there might be a shop charge */
949 struct monst *shkp = 0;
951 x = corpse->ox, y = corpse->oy;
952 if (costly_spot(x, y)
953 && (carried(corpse) ? corpse->unpaid : !corpse->no_charge))
954 shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
959 #if 1 /*JP*//*
\8e\80\91Ì
\96¼
\82Í
\90æ
\82É; Strcpy
\82É
\82È
\82é */
960 Strcpy(buf, corpse_xname(corpse, (const char *) 0, CXN_NO_PFX));
963 Strcpy(buf, one_of ? "one of " : "");
964 #else /*
\8cê
\8f\87\82Í
\95Ï
\82í
\82Á
\82Ä
\82¢
\82é */
966 Strcat(buf, "
\82Ì
\88ê
\82Â");
969 #if 0 /*JP*//*
\82±
\82±
\82Å
\81u
\82 \82È
\82½
\82Ì
\81v
\82Í
\95s
\8e©
\91R */
970 /* shk_your: "the " or "your " or "<mon>'s " or "<Shk>'s ".
971 If the result is "Shk's " then it will be ambiguous:
972 is Shk the mon carrying it, or does Shk's shop own it?
973 Let's not worry about that... */
974 (void) shk_your(eos(buf), corpse);
977 corpse->quan++; /* force plural */
978 #if 0 /*JP*//*
\8aù
\82É
\90Ý
\92è
\8dÏ
\82Ý */
979 Strcat(buf, corpse_xname(corpse, (const char *) 0, CXN_NO_PFX));
981 if (one_of) /* could be simplified to ''corpse->quan = 1L;'' */
984 pline("%s glows iridescently.", upstart(buf));
986 pline("%s
\82Í
\93ø
\90F
\82É
\8bP
\82¢
\82½
\81D", upstart(buf));
988 /* need some prior description of the corpse since
989 stolen_value() will refer to the object as "it" */
991 pline("A corpse is resuscitated.");
993 pline("
\8e\80\91Ì
\82ª
\91h
\90¶
\82µ
\82½
\81D");
995 /* don't charge for shopkeeper's own corpse if we just revived him */
996 if (shkp && mtmp != shkp)
997 (void) stolen_value(corpse, x, y, (boolean) shkp->mpeaceful,
1000 /* [we don't give any comparable message about the corpse for
1001 the !by_hero case because caller might have already done so] */
1004 /* handle recorporealization of an active ghost */
1005 if (has_omid(corpse)) {
1007 struct monst *ghost;
1010 (void) memcpy((genericptr_t) &m_id, (genericptr_t) OMID(corpse),
1012 ghost = find_mid(m_id, FM_FMON);
1013 if (ghost && ghost->data == &mons[PM_GHOST]) {
1014 if (canseemon(ghost))
1016 pline("%s is suddenly drawn into its former body!",
1018 pline("%s
\82Í
\93Ë
\91R
\82à
\82Æ
\82Ì
\91Ì
\82É
\88ø
\82«
\8d\9e\82Ü
\82ê
\82½
\81I",
1021 /* transfer the ghost's inventory along with it */
1022 while ((otmp = ghost->minvent) != 0) {
1023 obj_extract_self(otmp);
1024 add_to_minv(mtmp, otmp);
1026 /* tame the revived monster if its ghost was tame */
1027 if (ghost->mtame && !mtmp->mtame) {
1028 if (tamedog(mtmp, (struct obj *) 0)) {
1029 /* ghost's edog data is ignored */
1030 mtmp->mtame = ghost->mtame;
1033 /* was ghost, now alive, it's all very confusing */
1035 /* separate ghost monster no longer exists */
1041 /* monster retains its name */
1042 if (has_oname(corpse) && !unique_corpstat(mtmp->data))
1043 mtmp = christen_monst(mtmp, ONAME(corpse));
1044 /* partially eaten corpse yields wounded monster */
1046 mtmp->mhp = eaten_stat(mtmp->mhp, corpse);
1047 /* track that this monster was revived at least once */
1050 /* finally, get rid of the corpse--it's gone now */
1051 switch (corpse->where) {
1056 /* in case MON_AT+enexto for invisible mon */
1057 x = corpse->ox, y = corpse->oy;
1058 /* not useupf(), which charges */
1059 if (corpse->quan > 1L)
1060 corpse = splitobj(corpse, 1L);
1065 m_useup(corpse->ocarry, corpse);
1068 obj_extract_self(corpse);
1069 obfree(corpse, (struct obj *) 0);
1083 * Note: generic eggs with corpsenm set to NON_PM will never hatch.
1085 if (obj->otyp != EGG)
1087 if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE))
1088 attach_egg_hatch_timeout(obj, 0L);
1091 /* try to revive all corpses and eggs carried by `mon' */
1096 struct obj *otmp, *otmp2;
1097 struct monst *mtmp2;
1098 char owner[BUFSZ], corpse[BUFSZ];
1102 youseeit = (mon == &youmonst) ? TRUE : canseemon(mon);
1103 otmp2 = (mon == &youmonst) ? invent : mon->minvent;
1104 owner[0] = corpse[0] = '\0'; /* lint suppression */
1106 while ((otmp = otmp2) != 0) {
1108 if (otmp->otyp == EGG)
1110 if (otmp->otyp != CORPSE)
1112 /* save the name; the object is liable to go away */
1115 corpse_xname(otmp, (const char *) 0, CXN_SINGULAR));
1116 Shk_Your(owner, otmp); /* includes a trailing space */
1119 /* for a stack, only one is revived */
1120 if ((mtmp2 = revive(otmp, !context.mon_moving)) != 0) {
1124 pline("%s%s suddenly comes alive!", owner, corpse);
1126 pline("%s%s
\82Í
\93Ë
\91R
\90¶
\96½
\82ð
\91Ñ
\82Ñ
\82½
\81I", owner, corpse);
1127 else if (canseemon(mtmp2))
1129 pline("%s suddenly appears!", Amonnam(mtmp2));
1131 pline("%s
\82ª
\93Ë
\91R
\8c»
\82í
\82ê
\82½
\81I", Amonnam(mtmp2));
1137 /* cancel obj, possibly carried by you or a monster */
1140 register struct obj *obj;
1142 boolean u_ring = (obj == uleft || obj == uright);
1143 int otyp = obj->otyp;
1146 case RIN_GAIN_STRENGTH:
1147 if ((obj->owornmask & W_RING) && u_ring) {
1148 ABON(A_STR) -= obj->spe;
1152 case RIN_GAIN_CONSTITUTION:
1153 if ((obj->owornmask & W_RING) && u_ring) {
1154 ABON(A_CON) -= obj->spe;
1159 if ((obj->owornmask & W_RING) && u_ring) {
1160 ABON(A_CHA) -= obj->spe;
1164 case RIN_INCREASE_ACCURACY:
1165 if ((obj->owornmask & W_RING) && u_ring)
1166 u.uhitinc -= obj->spe;
1168 case RIN_INCREASE_DAMAGE:
1169 if ((obj->owornmask & W_RING) && u_ring)
1170 u.udaminc -= obj->spe;
1172 case GAUNTLETS_OF_DEXTERITY:
1173 if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
1174 ABON(A_DEX) -= obj->spe;
1178 case HELM_OF_BRILLIANCE:
1179 if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
1180 ABON(A_INT) -= obj->spe;
1181 ABON(A_WIS) -= obj->spe;
1185 /* case RIN_PROTECTION: not needed */
1187 if (objects[otyp].oc_magic
1188 || (obj->spe && (obj->oclass == ARMOR_CLASS
1189 || obj->oclass == WEAPON_CLASS || is_weptool(obj)))
1191 || otyp == POT_SICKNESS
1192 || (otyp == POT_WATER && (obj->blessed || obj->cursed))) {
1193 if (obj->spe != ((obj->oclass == WAND_CLASS) ? -1 : 0)
1194 && otyp != WAN_CANCELLATION /* can't cancel cancellation */
1195 && otyp != MAGIC_LAMP /* cancelling doesn't remove djinni */
1196 && otyp != CANDELABRUM_OF_INVOCATION) {
1197 costly_alteration(obj, COST_CANCEL);
1198 obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0;
1200 switch (obj->oclass) {
1202 costly_alteration(obj, COST_CANCEL);
1203 obj->otyp = SCR_BLANK_PAPER;
1207 if (otyp != SPE_CANCELLATION && otyp != SPE_NOVEL
1208 && otyp != SPE_BOOK_OF_THE_DEAD) {
1209 costly_alteration(obj, COST_CANCEL);
1210 obj->otyp = SPE_BLANK_PAPER;
1214 costly_alteration(obj,
1217 : obj->cursed ? COST_UNCURS : COST_UNBLSS);
1218 if (otyp == POT_SICKNESS || otyp == POT_SEE_INVISIBLE) {
1219 /* sickness is "biologically contaminated" fruit juice;
1220 cancel it and it just becomes fruit juice...
1221 whereas see invisible tastes like "enchanted" fruit
1222 juice, it similarly cancels */
1223 obj->otyp = POT_FRUIT_JUICE;
1225 obj->otyp = POT_WATER;
1226 obj->odiluted = 0; /* same as any other water */
1236 /* Remove a positive enchantment or charge from obj,
1237 * possibly carried by you or a monster
1240 drain_item(obj, by_you)
1246 /* Is this a charged/enchanted object? */
1248 || (!objects[obj->otyp].oc_charged && obj->oclass != WEAPON_CLASS
1249 && obj->oclass != ARMOR_CLASS && !is_weptool(obj))
1252 if (defends(AD_DRLI, obj) || defends_when_carried(AD_DRLI, obj)
1253 || obj_resists(obj, 10, 90))
1256 /* Charge for the cost of the object */
1258 costly_alteration(obj, COST_DRAIN);
1260 /* Drain the object and any implied effects */
1262 u_ring = (obj == uleft) || (obj == uright);
1263 switch (obj->otyp) {
1264 case RIN_GAIN_STRENGTH:
1265 if ((obj->owornmask & W_RING) && u_ring) {
1270 case RIN_GAIN_CONSTITUTION:
1271 if ((obj->owornmask & W_RING) && u_ring) {
1277 if ((obj->owornmask & W_RING) && u_ring) {
1282 case RIN_INCREASE_ACCURACY:
1283 if ((obj->owornmask & W_RING) && u_ring)
1286 case RIN_INCREASE_DAMAGE:
1287 if ((obj->owornmask & W_RING) && u_ring)
1290 case RIN_PROTECTION:
1292 context.botl = 1; /* bot() will recalc u.uac */
1294 case HELM_OF_BRILLIANCE:
1295 if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
1301 case GAUNTLETS_OF_DEXTERITY:
1302 if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
1318 obj_resists(obj, ochance, achance)
1320 int ochance, achance; /* percent chance for ordinary objects, artifacts */
1322 if (obj->otyp == AMULET_OF_YENDOR
1323 || obj->otyp == SPE_BOOK_OF_THE_DEAD
1324 || obj->otyp == CANDELABRUM_OF_INVOCATION
1325 || obj->otyp == BELL_OF_OPENING
1326 || (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm]))) {
1329 int chance = rn2(100);
1331 return (boolean) (chance < (obj->oartifact ? achance : ochance));
1341 if (context.bypasses && obj->bypass)
1344 if (obj->oclass == WAND_CLASS)
1345 zap_odds = 3; /* half-life = 2 zaps */
1346 else if (obj->cursed)
1347 zap_odds = 3; /* half-life = 2 zaps */
1348 else if (obj->blessed)
1349 zap_odds = 12; /* half-life = 8 zaps */
1351 zap_odds = 8; /* half-life = 6 zaps */
1353 /* adjust for "large" quantities of identical things */
1357 return (boolean) !rn2(zap_odds);
1360 /* Use up at least minwt number of things made of material mat.
1361 * There's also a chance that other stuff will be used up. Finally,
1362 * there's a random factor here to keep from always using the stuff
1363 * at the top of the pile.
1366 polyuse(objhdr, mat, minwt)
1370 register struct obj *otmp, *otmp2;
1372 for (otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) {
1373 otmp2 = otmp->nexthere;
1374 if (context.bypasses && otmp->bypass)
1376 if (otmp == uball || otmp == uchain)
1378 if (obj_resists(otmp, 0, 0))
1379 continue; /* preserve unique objects */
1381 if (otmp->otyp == SCR_MAIL)
1385 if (((int) objects[otmp->otyp].oc_material == mat)
1386 == (rn2(minwt + 1) != 0)) {
1387 /* appropriately add damage to bill */
1388 if (costly_spot(otmp->ox, otmp->oy)) {
1390 addtobill(otmp, FALSE, FALSE, FALSE);
1392 (void) stolen_value(otmp, otmp->ox, otmp->oy, FALSE,
1395 if (otmp->quan < LARGEST_INT)
1396 minwt -= (int) otmp->quan;
1405 * Polymorph some of the stuff in this pile into a monster, preferably
1406 * a golem of the kind okind.
1409 create_polymon(obj, okind)
1413 struct permonst *mdat = (struct permonst *) 0;
1415 const char *material;
1418 if (context.bypasses) {
1419 /* this is approximate because the "no golems" !obj->nexthere
1420 check below doesn't understand bypassed objects; but it
1421 should suffice since bypassed objects always end up as a
1422 consecutive group at the top of their pile */
1423 while (obj && obj->bypass)
1424 obj = obj->nexthere;
1427 /* no golems if you zap only one object -- not enough stuff */
1428 if (!obj || (!obj->nexthere && obj->quan == 1L))
1431 /* some of these choices are arbitrary */
1436 pm_index = PM_IRON_GOLEM;
1438 material = "metal ";
1440 material = "
\8bà
\91®";
1447 pm_index = rn2(2) ? PM_STONE_GOLEM : PM_CLAY_GOLEM;
1449 material = "lithic ";
1451 material = "
\8dz
\95¨";
1455 /* there is no flesh type, but all food is type 0, so we use it */
1456 pm_index = PM_FLESH_GOLEM;
1458 material = "organic ";
1460 material = "
\97L
\8b@
\95¨";
1463 pm_index = PM_WOOD_GOLEM;
1467 material = "
\96Ø
\8dÞ";
1470 pm_index = PM_LEATHER_GOLEM;
1472 material = "leather ";
1477 pm_index = PM_ROPE_GOLEM;
1479 material = "cloth ";
1484 pm_index = PM_SKELETON; /* nearest thing to "bone golem" */
1488 material = "
\8d\9c";
1491 pm_index = PM_GOLD_GOLEM;
1498 pm_index = PM_GLASS_GOLEM;
1500 material = "glassy ";
1502 material = "
\83K
\83\89\83X";
1505 pm_index = PM_PAPER_GOLEM;
1507 material = "paper ";
1509 material = "
\8e\86";
1512 /* if all else fails... */
1513 pm_index = PM_STRAW_GOLEM;
1517 material = "
\95¨
\91Ì";
1522 if (!(mvitals[pm_index].mvflags & G_GENOD))
1523 mdat = &mons[pm_index];
1525 mtmp = makemon(mdat, obj->ox, obj->oy, NO_MM_FLAGS);
1526 polyuse(obj, okind, (int) mons[pm_index].cwt);
1528 if (mtmp && cansee(mtmp->mx, mtmp->my)) {
1530 pline("Some %sobjects meld, and %s arises from the pile!", material,
1533 pline("
\82¢
\82
\82Â
\82©
\82Ì%s
\82ª
\97n
\82¯
\81C
\82»
\82Ì
\8eR
\82©
\82ç%s
\82ª
\8c»
\82í
\82ê
\82½
\81I", material,
1539 /* Assumes obj is on the floor. */
1547 if (obj->otyp == SCR_MAIL)
1552 if (poly_zapped < 0) {
1553 /* some may metamorphosize */
1554 for (i = obj->quan; i; i--)
1555 if (!rn2(Luck + 45)) {
1556 poly_zapped = objects[obj->otyp].oc_material;
1561 /* if quan > 1 then some will survive intact */
1562 if (obj->quan > 1L) {
1563 if (obj->quan > LARGEST_INT)
1564 obj = splitobj(obj, (long) rnd(30000));
1566 obj = splitobj(obj, (long) rnd((int) obj->quan - 1));
1569 /* appropriately add damage to bill */
1570 if (costly_spot(obj->ox, obj->oy)) {
1572 addtobill(obj, FALSE, FALSE, FALSE);
1574 (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE);
1577 /* zap the object */
1581 /* classes of items whose current charge count carries over across polymorph
1583 static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS,
1587 * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT
1588 * then pick random object from the source's class (this is the standard
1589 * "polymorph" case). If ID is set to a specific object, inhibit fusing
1590 * n objects into 1. This could have been added as a flag, but currently
1591 * it is tied to not being the standard polymorph case. The new polymorphed
1592 * object replaces obj in its link chains. Return value is a pointer to
1595 * This should be safe to call for an object anywhere.
1603 xchar ox = 0, oy = 0;
1604 long old_wornmask, new_wornmask = 0L;
1605 boolean can_merge = (id == STRANGE_OBJECT);
1606 int obj_location = obj->where;
1608 if (obj->otyp == BOULDER)
1610 if (id == STRANGE_OBJECT) { /* preserve symbol */
1612 unsigned magic_obj = objects[obj->otyp].oc_magic;
1614 if (obj->otyp == UNICORN_HORN && obj->degraded_horn)
1616 /* Try up to 3 times to make the magic-or-not status of
1617 the new item be the same as it was for the old one. */
1618 otmp = (struct obj *) 0;
1622 otmp = mkobj(obj->oclass, FALSE);
1623 } while (--try_limit > 0
1624 && objects[otmp->otyp].oc_magic != magic_obj);
1626 /* literally replace obj with this new thing */
1627 otmp = mksobj(id, FALSE, FALSE);
1628 /* Actually more things use corpsenm but they polymorph differently */
1629 #define USES_CORPSENM(typ) \
1630 ((typ) == CORPSE || (typ) == STATUE || (typ) == FIGURINE)
1632 if (USES_CORPSENM(obj->otyp) && USES_CORPSENM(id))
1633 set_corpsenm(otmp, obj->corpsenm);
1634 #undef USES_CORPSENM
1637 /* preserve quantity */
1638 otmp->quan = obj->quan;
1639 /* preserve the shopkeepers (lack of) interest */
1640 otmp->no_charge = obj->no_charge;
1641 /* preserve inventory letter if in inventory */
1642 if (obj_location == OBJ_INVENT)
1643 otmp->invlet = obj->invlet;
1645 /* You can't send yourself 100 mail messages and then
1646 * polymorph them into useful scrolls
1648 if (obj->otyp == SCR_MAIL) {
1649 otmp->otyp = SCR_MAIL;
1654 /* avoid abusing eggs laid by you */
1655 if (obj->otyp == EGG && obj->spe) {
1656 int mnum, tryct = 100;
1658 /* first, turn into a generic egg */
1659 if (otmp->otyp == EGG)
1663 otmp->owt = weight(otmp);
1665 otmp->corpsenm = NON_PM;
1668 /* now change it into something laid by the hero */
1670 mnum = can_be_hatched(random_monster(rn2));
1671 if (mnum != NON_PM && !dead_species(mnum, TRUE)) {
1672 otmp->spe = 1; /* laid by hero */
1673 set_corpsenm(otmp, mnum); /* also sets hatch timer */
1679 /* keep special fields (including charges on wands) */
1680 if (index(charged_objs, otmp->oclass))
1681 otmp->spe = obj->spe;
1682 otmp->recharged = obj->recharged;
1684 otmp->cursed = obj->cursed;
1685 otmp->blessed = obj->blessed;
1687 if (erosion_matters(otmp)) {
1688 if (is_flammable(otmp) || is_rustprone(otmp))
1689 otmp->oeroded = obj->oeroded;
1690 if (is_corrodeable(otmp) || is_rottable(otmp))
1691 otmp->oeroded2 = obj->oeroded2;
1692 if (is_damageable(otmp))
1693 otmp->oerodeproof = obj->oerodeproof;
1696 /* Keep chest/box traps and poisoned ammo if we may */
1697 if (obj->otrapped && Is_box(otmp))
1698 otmp->otrapped = TRUE;
1700 if (obj->opoisoned && is_poisonable(otmp))
1701 otmp->opoisoned = TRUE;
1703 if (id == STRANGE_OBJECT && obj->otyp == CORPSE) {
1704 /* turn crocodile corpses into shoes */
1705 if (obj->corpsenm == PM_CROCODILE) {
1706 otmp->otyp = LOW_BOOTS;
1707 otmp->oclass = ARMOR_CLASS;
1710 otmp->oerodeproof = TRUE;
1712 otmp->cursed = FALSE;
1716 /* no box contents --KAA */
1717 if (Has_contents(otmp))
1718 delete_contents(otmp);
1720 /* 'n' merged objects may be fused into 1 object */
1721 if (otmp->quan > 1L && (!objects[otmp->otyp].oc_merge
1722 || (can_merge && otmp->quan > (long) rn2(1000))))
1725 switch (otmp->oclass) {
1727 if (otmp->otyp == MAGIC_LAMP) {
1728 otmp->otyp = OIL_LAMP;
1729 otmp->age = 1500L; /* "best" oil lamp possible */
1730 } else if (otmp->otyp == MAGIC_MARKER) {
1731 otmp->recharged = 1; /* degraded quality */
1733 /* don't care about the recharge count of other tools */
1737 while (otmp->otyp == WAN_WISHING || otmp->otyp == WAN_POLYMORPH)
1738 otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
1739 /* altering the object tends to degrade its quality
1740 (analogous to spellbook `read count' handling) */
1741 if ((int) otmp->recharged < rn2(7)) /* recharge_limit */
1746 while (otmp->otyp == POT_POLYMORPH)
1747 otmp->otyp = rnd_class(POT_GAIN_ABILITY, POT_WATER);
1751 while (otmp->otyp == SPE_POLYMORPH)
1752 otmp->otyp = rnd_class(SPE_DIG, SPE_BLANK_PAPER);
1753 /* reduce spellbook abuse; non-blank books degrade */
1754 if (otmp->otyp != SPE_BLANK_PAPER) {
1755 otmp->spestudied = obj->spestudied + 1;
1756 if (otmp->spestudied > MAX_SPELL_STUDY) {
1757 otmp->otyp = SPE_BLANK_PAPER;
1758 /* writing a new book over it will yield an unstudied
1759 one; re-polymorphing this one as-is may or may not
1760 get something non-blank */
1761 otmp->spestudied = rn2(otmp->spestudied);
1767 if (otmp->quan > (long) rnd(4)
1768 && objects[obj->otyp].oc_material == MINERAL
1769 && objects[otmp->otyp].oc_material != MINERAL) {
1770 otmp->otyp = ROCK; /* transmutation backfired */
1771 otmp->quan /= 2L; /* some material has been lost */
1776 /* update the weight */
1777 otmp->owt = weight(otmp);
1780 * ** we are now done adjusting the object (except possibly wearing it) **
1783 (void) get_obj_location(obj, &ox, &oy, BURIED_TOO | CONTAINED_TOO);
1784 old_wornmask = obj->owornmask & ~(W_ART | W_ARTI);
1785 /* swap otmp for obj */
1786 replace_object(obj, otmp);
1787 if (obj_location == OBJ_INVENT) {
1789 * We may need to do extra adjustments for the hero if we're
1790 * messing with the hero's inventory. The following calls are
1791 * equivalent to calling freeinv on obj and addinv on otmp,
1792 * while doing an in-place swap of the actual objects.
1798 * Handle polymorph of worn item. Stone-to-flesh cast on self can
1799 * affect multiple objects at once, but their new forms won't
1800 * produce any side-effects. A single worn item dipped into potion
1801 * of polymorph can produce side-effects but those won't yield out
1802 * of sequence messages because current polymorph is finished.
1805 boolean was_twohanded = bimanual(obj), was_twoweap = u.twoweap;
1807 /* wearslot() returns a mask which might have multiple bits set;
1808 narrow that down to the bit(s) currently in use */
1809 new_wornmask = wearslot(otmp) & old_wornmask;
1810 remove_worn_item(obj, TRUE);
1811 /* if the new form can be worn in the same slot, make it so */
1812 if ((new_wornmask & W_WEP) != 0L) {
1813 if (was_twohanded || !bimanual(otmp) || !uarms)
1815 if (was_twoweap && uwep && !bimanual(uwep))
1817 } else if ((new_wornmask & W_SWAPWEP) != 0L) {
1818 if (was_twohanded || !bimanual(otmp))
1820 if (was_twoweap && uswapwep)
1822 } else if ((new_wornmask & W_QUIVER) != 0L) {
1824 } else if (new_wornmask) {
1825 setworn(otmp, new_wornmask);
1826 /* set_wear() might result in otmp being destroyed if
1827 worn amulet has been turned into an amulet of change */
1829 otmp = wearmask_to_obj(new_wornmask); /* might be Null */
1831 } /* old_wornmask */
1832 } else if (obj_location == OBJ_FLOOR) {
1833 if (obj->otyp == BOULDER && otmp->otyp != BOULDER
1834 && !does_block(ox, oy, &levl[ox][oy]))
1835 unblock_point(ox, oy);
1836 else if (obj->otyp != BOULDER && otmp->otyp == BOULDER)
1837 /* (checking does_block() here would be redundant) */
1838 block_point(ox, oy);
1841 /* note: if otmp is gone, billing for it was handled by useup() */
1842 if (((otmp && !carried(otmp)) || obj->unpaid) && costly_spot(ox, oy)) {
1843 struct monst *shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE));
1845 if ((!obj->no_charge
1846 || (Has_contents(obj)
1847 && (contained_cost(obj, shkp, 0L, FALSE, FALSE) != 0L)))
1848 && inhishop(shkp)) {
1849 if (shkp->mpeaceful) {
1851 && (*in_rooms(u.ux, u.uy, 0)
1852 == *in_rooms(shkp->mx, shkp->my, 0))
1853 && !costly_spot(u.ux, u.uy)) {
1854 make_angry_shk(shkp, ox, oy);
1857 pline("%s gets angry!", Monnam(shkp));
1859 pline("%s
\82Í
\8c\83\93{
\82µ
\82½
\81I", Monnam(shkp));
1864 Norep("%s is furious!", Monnam(shkp));
1866 Norep("%s
\82Í
\93{
\82Á
\82½
\81I", Monnam(shkp));
1873 /* stone-to-flesh spell hits and maybe transforms or animates obj */
1875 stone_to_flesh_obj(obj)
1878 int res = 1; /* affected object by default */
1879 struct permonst *ptr;
1880 struct monst *mon, *shkp;
1883 boolean smell = FALSE, golem_xform = FALSE;
1885 if (objects[obj->otyp].oc_material != MINERAL
1886 && objects[obj->otyp].oc_material != GEMSTONE)
1888 /* Heart of Ahriman usually resists; ordinary items rarely do */
1889 if (obj_resists(obj, 2, 98))
1892 (void) get_obj_location(obj, &oox, &ooy, 0);
1893 /* add more if stone objects are added.. */
1894 switch (objects[obj->otyp].oc_class) {
1895 case ROCK_CLASS: /* boulders and statues */
1896 case TOOL_CLASS: /* figurines */
1897 if (obj->otyp == BOULDER) {
1898 obj = poly_obj(obj, HUGE_CHUNK_OF_MEAT);
1900 } else if (obj->otyp == STATUE || obj->otyp == FIGURINE) {
1901 ptr = &mons[obj->corpsenm];
1902 if (is_golem(ptr)) {
1903 golem_xform = (ptr != &mons[PM_FLESH_GOLEM]);
1904 } else if (vegetarian(ptr)) {
1905 /* Don't animate monsters that aren't flesh */
1906 obj = poly_obj(obj, MEATBALL);
1910 if (obj->otyp == STATUE) {
1911 /* animate_statue() forces all golems to become flesh golems */
1912 mon = animate_statue(obj, oox, ooy, ANIMATE_SPELL, (int *) 0);
1913 } else { /* (obj->otyp == FIGURINE) */
1915 ptr = &mons[PM_FLESH_GOLEM];
1916 mon = makemon(ptr, oox, ooy, NO_MINVENT);
1918 if (costly_spot(oox, ooy)
1919 && (carried(obj) ? obj->unpaid : !obj->no_charge)) {
1920 shkp = shop_keeper(*in_rooms(oox, ooy, SHOPBASE));
1921 stolen_value(obj, oox, ooy,
1922 (shkp && shkp->mpeaceful), FALSE);
1925 obj_stop_timers(obj);
1930 if (cansee(mon->mx, mon->my))
1932 pline_The("figurine %sanimates!",
1933 golem_xform ? "turns to flesh and " : "");
1935 pline_The("
\90l
\8c`
\82Í%s
\93®
\82«
\82¾
\82µ
\82½
\81I",
1936 golem_xform ? "
\90Î
\89»
\82ª
\89ð
\82¯
\82Ä" : "");
1942 /* this golem handling is redundant... */
1943 if (is_golem(ptr) && ptr != &mons[PM_FLESH_GOLEM])
1944 (void) newcham(mon, &mons[PM_FLESH_GOLEM], TRUE, FALSE);
1945 } else if ((ptr->geno & (G_NOCORPSE | G_UNIQ)) != 0) {
1946 /* didn't revive but can't leave corpse either */
1949 /* unlikely to get here since genociding monsters also
1950 sets the G_NOCORPSE flag; drop statue's contents */
1951 while ((item = obj->cobj) != 0) {
1952 bypass_obj(item); /* make stone-to-flesh miss it */
1953 obj_extract_self(item);
1954 place_object(item, oox, ooy);
1956 obj = poly_obj(obj, CORPSE);
1958 } else { /* miscellaneous tool or unexpected rock... */
1962 /* maybe add weird things to become? */
1963 case RING_CLASS: /* some of the rings are stone */
1964 obj = poly_obj(obj, MEAT_RING);
1967 case WAND_CLASS: /* marble wand */
1968 obj = poly_obj(obj, MEAT_STICK);
1971 case GEM_CLASS: /* stones & gems */
1972 obj = poly_obj(obj, MEATBALL);
1975 case WEAPON_CLASS: /* crysknife */
1983 /* non-meat eaters smell meat, meat eaters smell its flavor;
1984 monks are considered non-meat eaters regardless of behavior;
1985 other roles are non-meat eaters if they haven't broken
1986 vegetarian conduct yet (or if poly'd into non-carnivorous/
1987 non-omnivorous form, regardless of whether it's herbivorous,
1988 non-eating, or something stranger) */
1989 if (Role_if(PM_MONK) || !u.uconduct.unvegetarian
1990 || !carnivorous(youmonst.data))
1992 Norep("You smell the odor of meat.");
1994 Norep("
\93÷
\82Ì
\88«
\8fL
\82ª
\95Y
\82Á
\82½
\81D");
1997 Norep("You smell a delicious smell.");
1999 Norep("
\82·
\82Î
\82ç
\82µ
\82¢
\8d\81\82è
\82¾
\81I");
2006 * Object obj was hit by the effect of the wand/spell otmp. Return
2007 * non-zero if the wand/spell had any effect.
2011 struct obj *obj, *otmp;
2013 int res = 1; /* affected object by default */
2014 boolean learn_it = FALSE, maybelearnit;
2016 /* fundamental: a wand effect hitting itself doesn't do anything;
2017 otherwise we need to guard against accessing otmp after something
2018 strange has happened to it (along the lines of polymorph or
2019 stone-to-flesh [which aren't good examples since polymorph wands
2020 aren't affected by polymorph zaps and stone-to-flesh isn't
2021 available in wand form, but the concept still applies...]) */
2026 /* The bypass bit is currently only used as follows:
2028 * POLYMORPH - When a monster being polymorphed drops something
2029 * from its inventory as a result of the change.
2030 * If the items fall to the floor, they are not
2031 * subject to direct subsequent polymorphing
2032 * themselves on that same zap. This makes it
2033 * consistent with items that remain in the monster's
2034 * inventory. They are not polymorphed either.
2035 * UNDEAD_TURNING - When an undead creature gets killed via
2036 * undead turning, prevent its corpse from being
2037 * immediately revived by the same effect.
2038 * STONE_TO_FLESH - If a statue can't be revived, its
2039 * contents get dropped before turning it into
2040 * meat; prevent those contents from being hit.
2041 * retouch_equipment() - bypass flag is used to track which
2042 * items have been handled (bhito isn't involved).
2043 * menu_drop(), askchain() - inventory traversal where multiple
2044 * Drop can alter the invent chain while traversal
2045 * is in progress (bhito isn't involved).
2046 * destroy_item(), destroy_mitem() - inventory traversal where
2047 * item destruction can trigger drop or destruction of
2048 * other item(s) and alter the invent or mon->minvent
2049 * chain, possibly recursively.
2051 * The bypass bit on all objects is reset each turn, whenever
2052 * context.bypasses is set.
2054 * We check the obj->bypass bit above AND context.bypasses
2055 * as a safeguard against any stray occurrence left in an obj
2056 * struct someplace, although that should never happen.
2058 if (context.bypasses) {
2061 debugpline1("%s for a moment.", Tobjnam(obj, "pulsate"));
2067 * Some parts of this function expect the object to be on the floor
2068 * obj->{ox,oy} to be valid. The exception to this (so far) is
2069 * for the STONE_TO_FLESH spell.
2071 if (!(obj->where == OBJ_FLOOR || otmp->otyp == SPE_STONE_TO_FLESH))
2072 impossible("bhito: obj is not floor or Stone To Flesh spell");
2076 } else if (obj == uchain) {
2077 if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) {
2083 switch (otmp->otyp) {
2086 if (obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH
2087 || obj->otyp == POT_POLYMORPH || obj_resists(obj, 5, 95)) {
2092 u.uconduct.polypiles++;
2093 /* any saved lock context will be dangerously obsolete */
2095 (void) boxlock(obj, otmp);
2097 if (obj_shudders(obj)) {
2098 boolean cover = ((obj == level.objects[u.ux][u.uy])
2100 && hides_under(youmonst.data));
2102 if (cansee(obj->ox, obj->oy))
2105 /* eek - your cover might have been blown */
2107 (void) hideunder(&youmonst);
2110 obj = poly_obj(obj, STRANGE_OBJECT);
2111 newsym(obj->ox, obj->oy);
2115 /* target object has now been "seen (up close)" */
2117 if (Is_container(obj) || obj->otyp == STATUE) {
2118 obj->cknown = obj->lknown = 1;
2121 pline("%s empty.", Tobjnam(obj, "are"));
2123 pline("%s
\82Í
\8bó
\82Á
\82Û
\82¾
\81D", xname(obj));
2124 } else if (SchroedingersBox(obj)) {
2125 /* we don't want to force alive vs dead
2126 determination for Schroedinger's Cat here,
2127 so just make probing be inconclusive for it */
2129 You("aren't sure whether %s has %s or its corpse inside.",
2131 /* unfortunately, we can't tell whether rndmonnam()
2132 picks a form which can't leave a corpse */
2133 an(Hallucination ? rndmonnam((char *) 0) : "cat"));
2135 pline("%s
\82É%s
\82ª
\93ü
\82Á
\82Ä
\82¢
\82é
\82Ì
\82©
\82»
\82Ì
\8e\80\91Ì
\82ª
\93ü
\82Á
\82Ä
\82¢
\82é
\82Ì
\82©
\82í
\82©
\82ç
\82È
\82¢
\81D",
2137 /* unfortunately, we can't tell whether rndmonnam()
2138 picks a form which can't leave a corpse */
2139 Hallucination ? rndmonnam((char *) 0) : "
\94L");
2145 /* view contents (not recursively) */
2146 for (o = obj->cobj; o; o = o->nobj)
2147 o->dknown = 1; /* "seen", even if blind */
2148 (void) display_cinventory(obj);
2156 case SPE_FORCE_BOLT:
2157 /* learn the type if you see or hear something break
2158 (the sound could be implicit) */
2159 maybelearnit = cansee(obj->ox, obj->oy) || !Deaf;
2160 if (obj->otyp == BOULDER) {
2161 if (cansee(obj->ox, obj->oy))
2163 pline_The("boulder falls apart.");
2165 pline_The("
\8aâ
\82Í
\82Î
\82ç
\82Î
\82ç
\82É
\82È
\82Á
\82½
\81D");
2168 You_hear("a crumbling sound.");
2170 You_hear("
\89½
\82©
\82ª
\8dÓ
\82¯
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D");
2172 } else if (obj->otyp == STATUE) {
2173 if (break_statue(obj)) {
2174 if (cansee(obj->ox, obj->oy)) {
2177 pline_The("%s shatters.", rndmonnam(NULL));
2179 pline_The("%s
\82Í
\95²
\81X
\82É
\82È
\82Á
\82½
\81D", rndmonnam(NULL));
2182 pline_The("statue shatters.");
2184 pline_The("
\90Î
\91\9c\82Í
\95²
\81X
\82É
\82È
\82Á
\82½
\81D");
2187 You_hear("a crumbling sound.");
2189 You_hear("
\89½
\82©
\82ª
\8dÓ
\82¯
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D");
2194 if (context.mon_moving
2195 ? !breaks(obj, obj->ox, obj->oy)
2196 : !hero_breaks(obj, obj->ox, obj->oy, FALSE))
2197 maybelearnit = FALSE; /* nothing broke */
2199 newsym_force(oox,ooy);
2205 case WAN_CANCELLATION:
2206 case SPE_CANCELLATION:
2209 newsym(obj->ox, obj->oy); /* might change color */
2212 case SPE_DRAIN_LIFE:
2213 (void) drain_item(obj, TRUE);
2215 case WAN_TELEPORTATION:
2216 case SPE_TELEPORT_AWAY:
2219 case WAN_MAKE_INVISIBLE:
2221 case WAN_UNDEAD_TURNING:
2222 case SPE_TURN_UNDEAD:
2223 if (obj->otyp == EGG) {
2225 } else if (obj->otyp == CORPSE) {
2228 int corpsenm = corpse_revive_type(obj);
2229 char *corpsname = cxname_singular(obj);
2231 /* get corpse's location before revive() uses it up */
2232 if (!get_obj_location(obj, &ox, &oy, 0))
2233 ox = obj->ox, oy = obj->oy; /* won't happen */
2235 mtmp = revive(obj, TRUE);
2237 res = 0; /* no monster implies corpse was left intact */
2239 if (cansee(ox, oy)) {
2240 if (canspotmon(mtmp)) {
2242 pline("%s is resurrected!",
2243 upstart(noname_monnam(mtmp, ARTICLE_THE)));
2245 pline("%s
\82Í
\90¶
\82«
\95Ô
\82Á
\82½
\81I",
2246 upstart(noname_monnam(mtmp, ARTICLE_THE)));
2250 /* saw corpse but don't see monster: maybe
2251 mtmp is invisible, or has been placed at
2252 a different spot than <ox,oy> */
2253 if (!type_is_pname(&mons[corpsenm]))
2254 corpsname = The(corpsname);
2256 pline("%s disappears.", corpsname);
2258 pline("%s
\82Í
\8fÁ
\82¦
\82½
\81D", corpsname);
2261 /* couldn't see corpse's location */
2262 if (Role_if(PM_HEALER) && !Deaf
2263 && !nonliving(&mons[corpsenm])) {
2264 if (!type_is_pname(&mons[corpsenm]))
2265 corpsname = an(corpsname);
2268 You_hear("%s reviving.", corpsname);
2270 You_hear("%s
\82ª
\90¶
\82«
\95Ô
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D", corpsname);
2273 You_hear("a defibrillator.");
2275 You_hear("
\8f\9c\8d×
\93®
\8aí
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
2278 if (canspotmon(mtmp))
2279 /* didn't see corpse but do see monster: it
2280 has been placed somewhere other than <ox,oy>
2281 or blind hero spots it with ESP */
2283 pline("%s appears.", Monnam(mtmp));
2285 pline("%s
\82ª
\8c»
\82ê
\82½
\81D", Monnam(mtmp));
2288 exercise(A_WIS, TRUE);
2295 case SPE_WIZARD_LOCK:
2297 res = boxlock(obj, otmp);
2303 case WAN_SLOW_MONSTER: /* no effect on objects */
2304 case SPE_SLOW_MONSTER:
2305 case WAN_SPEED_MONSTER:
2308 case SPE_EXTRA_HEALING:
2311 case SPE_STONE_TO_FLESH:
2312 res = stone_to_flesh_obj(obj);
2315 impossible("What an interesting effect (%d)", otmp->otyp);
2318 /* if effect was observable then discover the wand type provided
2319 that the wand itself has been seen */
2325 /* returns nonzero if something was hit */
2327 bhitpile(obj, fhito, tx, ty, zz)
2329 int FDECL((*fhito), (OBJ_P, OBJ_P));
2333 int hitanything = 0;
2334 register struct obj *otmp, *next_obj;
2336 if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) {
2337 struct trap *t = t_at(tx, ty);
2339 /* We can't settle for the default calling sequence of
2340 bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
2341 because that last call might end up operating on our `next_obj'
2342 (below), rather than on the current object, if it happens to
2343 encounter a statue which mustn't become animated. */
2344 if (t && t->ttyp == STATUE_TRAP
2345 && activate_statue_trap(t, tx, ty, TRUE))
2350 for (otmp = level.objects[tx][ty]; otmp; otmp = next_obj) {
2351 next_obj = otmp->nexthere;
2352 /* for zap downwards, don't hit object poly'd hero is hiding under */
2353 if (zz > 0 && u.uundetected && otmp == level.objects[u.ux][u.uy]
2354 && hides_under(youmonst.data))
2357 hitanything += (*fhito)(otmp, obj);
2359 if (poly_zapped >= 0)
2360 create_polymon(level.objects[tx][ty], poly_zapped);
2366 * zappable - returns 1 if zap is available, 0 otherwise.
2367 * it removes a charge from the wand if zappable.
2368 * added by GAN 11/03/86
2372 register struct obj *wand;
2374 if (wand->spe < 0 || (wand->spe == 0 && rn2(121)))
2378 You("wrest one last charge from the worn-out wand.");
2380 You("
\8eg
\82¢
\82«
\82Á
\82½
\8fñ
\82©
\82ç
\8dÅ
\8cã
\82Ì
\97Í
\82ð
\82µ
\82Ú
\82è
\82Æ
\82Á
\82½
\81D");
2386 * zapnodir - zaps a NODIR wand/spell.
2387 * added by GAN 11/03/86
2391 register struct obj *obj;
2393 boolean known = FALSE;
2395 switch (obj->otyp) {
2401 if (lightdamage(obj, TRUE, 5))
2404 case WAN_SECRET_DOOR_DETECTION:
2405 case SPE_DETECT_UNSEEN:
2411 case WAN_CREATE_MONSTER:
2412 known = create_critters(rn2(23) ? 1 : rn1(7, 2),
2413 (struct permonst *) 0, FALSE);
2417 if (Luck + rn2(5) < 0) {
2419 pline("Unfortunately, nothing happens.");
2421 pline("
\8ec
\94O
\82È
\82ª
\82ç
\81C
\89½
\82à
\8bN
\82«
\82È
\82©
\82Á
\82½
\81D");
2426 case WAN_ENLIGHTENMENT:
2429 You_feel("self-knowledgeable...");
2431 You("
\8e©
\95ª
\8e©
\90g
\82ª
\94»
\82é
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D
\81D
\81D");
2432 display_nhwindow(WIN_MESSAGE, FALSE);
2433 enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS);
2435 pline_The("feeling subsides.");
2437 pline("
\82»
\82Ì
\8a´
\82¶
\82Í
\82È
\82
\82È
\82Á
\82½
\81D");
2438 exercise(A_WIS, TRUE);
2442 if (!objects[obj->otyp].oc_name_known)
2443 more_experienced(0, 10);
2444 /* effect was observable; discover the wand type provided
2445 that the wand itself has been seen */
2456 otmp->in_use = TRUE; /* in case losehp() is fatal */
2458 pline("%s suddenly explodes!", The(xname(otmp)));
2460 pline("%s
\82Í
\93Ë
\91R
\94\9a\94
\82µ
\82½
\81I", xname(otmp));
2461 dmg = d(otmp->spe + 2, 6);
2463 losehp(Maybe_Half_Phys(dmg), "exploding wand", KILLED_BY_AN);
2465 losehp(Maybe_Half_Phys(dmg), "
\8fñ
\82Ì
\94\9a\94
\82Å", KILLED_BY_AN);
2469 static NEARDATA const char zap_syms[] = { WAND_CLASS, 0 };
2471 /* 'z' command (or 'y' if numbed_pad==-1) */
2475 register struct obj *obj;
2478 if (check_capacity((char *) 0))
2480 obj = getobj(zap_syms, "zap");
2486 /* zappable addition done by GAN 11/03/86 */
2488 pline1(nothing_happens);
2489 else if (obj->cursed && !rn2(WAND_BACKFIRE_CHANCE)) {
2490 backfire(obj); /* the wand blows up in your face! */
2491 exercise(A_STR, FALSE);
2493 } else if (!(objects[obj->otyp].oc_dir == NODIR) && !getdir((char *) 0)) {
2496 pline("%s glows and fades.", The(xname(obj)));
2498 pline("%s
\82Í
\88ê
\8fu
\8bP
\82¢
\82½
\81D", The(xname(obj)));
2499 /* make him pay for knowing !NODIR */
2500 } else if (!u.dx && !u.dy && !u.dz
2501 && !(objects[obj->otyp].oc_dir == NODIR)) {
2502 if ((damage = zapyourself(obj, TRUE)) != 0) {
2506 Sprintf(buf, "zapped %sself with a wand", uhim());
2507 losehp(Maybe_Half_Phys(damage), buf, NO_KILLER_PREFIX);
2509 losehp(Maybe_Half_Phys(damage),
2510 "
\8e©
\95ª
\8e©
\90g
\82Ì
\8fñ
\82Ì
\97Í
\82ð
\97\81\82Ñ
\82Ä", KILLED_BY);
2514 /* Are we having fun yet?
2515 * weffects -> buzz(obj->otyp) -> zhitm (temple priest) ->
2516 * attack -> hitum -> known_hitum -> ghod_hitsu ->
2517 * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) ->
2518 * useup -> obfree -> dealloc_obj -> free(obj)
2525 if (obj && obj->spe < 0) {
2527 pline("%s to dust.", Tobjnam(obj, "turn"));
2529 pline("%s
\82Í
\82¿
\82è
\82Æ
\82È
\82Á
\82½
\81D", xname(obj));
2532 update_inventory(); /* maybe used a charge */
2537 zapyourself(obj, ordinary)
2541 boolean learn_it = FALSE;
2544 switch (obj->otyp) {
2546 case SPE_FORCE_BOLT:
2549 shieldeff(u.ux, u.uy);
2553 pline("
\83{
\83C
\83\93\81I");
2557 You("bash yourself!");
2559 You("
\8e©
\95ª
\8e©
\90g
\82ð
\91Å
\82¿
\82Â
\82¯
\82½
\81I");
2562 damage = d(1 + obj->spe, 6);
2563 exercise(A_STR, FALSE);
2569 if (!Shock_resistance) {
2571 You("shock yourself!");
2573 You("
\93d
\8c\82\82ð
\82¤
\82¯
\82½
\81I");
2575 exercise(A_CON, FALSE);
2577 shieldeff(u.ux, u.uy);
2579 You("zap yourself, but seem unharmed.");
2581 You("
\8e©
\95ª
\82É
\8fñ
\82ð
\82Ó
\82è
\82©
\82´
\82µ
\82½
\82ª
\81C
\89ö
\89ä
\82Í
\82µ
\82È
\82©
\82Á
\82½
\82æ
\82¤
\82¾
\81D");
2582 ugolemeffects(AD_ELEC, d(12, 6));
2584 destroy_item(WAND_CLASS, AD_ELEC);
2585 destroy_item(RING_CLASS, AD_ELEC);
2586 (void) flashburn((long) rnd(100));
2591 You("explode a fireball on top of yourself!");
2593 Your("
\93ª
\8fã
\82Å
\89Î
\82Ì
\8bÊ
\82ª
\94\9a\94
\82µ
\82½
\81I");
2594 explode(u.ux, u.uy, 11, d(6, 6), WAND_CLASS, EXPL_FIERY);
2599 if (Fire_resistance) {
2600 shieldeff(u.ux, u.uy);
2602 You_feel("rather warm.");
2604 You("
\82¿
\82å
\82Á
\82Æ
\92g
\82©
\82
\8a´
\82¶
\82½
\81D");
2605 ugolemeffects(AD_FIRE, d(12, 6));
2608 pline("You've set yourself afire!");
2610 You("
\89\8a\82É
\82Â
\82Â
\82Ü
\82ê
\82½
\81I");
2614 (void) burnarmor(&youmonst);
2615 destroy_item(SCROLL_CLASS, AD_FIRE);
2616 destroy_item(POTION_CLASS, AD_FIRE);
2617 destroy_item(SPBOOK_CLASS, AD_FIRE);
2618 destroy_item(FOOD_CLASS, AD_FIRE); /* only slime for now */
2622 case SPE_CONE_OF_COLD:
2625 if (Cold_resistance) {
2626 shieldeff(u.ux, u.uy);
2628 You_feel("a little chill.");
2630 You("
\82¿
\82å
\82Á
\82Æ
\97â
\82½
\82
\8a´
\82¶
\82½
\81D");
2631 ugolemeffects(AD_COLD, d(12, 6));
2634 You("imitate a popsicle!");
2636 You("
\83A
\83C
\83X
\83L
\83\83\83\93\83f
\81[
\82Ì
\82æ
\82¤
\82É
\82È
\82Á
\82½
\81I");
2639 destroy_item(POTION_CLASS, AD_COLD);
2642 case WAN_MAGIC_MISSILE:
2643 case SPE_MAGIC_MISSILE:
2646 shieldeff(u.ux, u.uy);
2648 pline_The("missiles bounce!");
2650 pline("
\96\82\96@
\82Ì
\96î
\82Í
\82Í
\82Ë
\82©
\82¦
\82Á
\82½
\81I");
2654 pline("Idiot! You've shot yourself!");
2656 pline("
\89½
\82â
\82Á
\82Ä
\82ñ
\82¾
\81I
\82 \82È
\82½
\82Í
\8e©
\95ª
\8e©
\90g
\82ð
\8c\82\82Á
\82½
\81I");
2668 case WAN_CANCELLATION:
2669 case SPE_CANCELLATION:
2670 (void) cancel_monst(&youmonst, obj, TRUE, TRUE, TRUE);
2673 case SPE_DRAIN_LIFE:
2674 if (!Drain_resistance) {
2675 learn_it = TRUE; /* (no effect for spells...) */
2677 losexp("life drainage");
2679 losexp("
\90¶
\96½
\97Í
\82ð
\8bz
\8eû
\82³
\82ê
\82Ä");
2681 damage = 0; /* No additional damage */
2684 case WAN_MAKE_INVISIBLE: {
2685 /* have to test before changing HInvis but must change
2686 * HInvis before doing newsym().
2688 int msg = !Invis && !Blind && !BInvis;
2690 if (BInvis && uarmc->otyp == MUMMY_WRAPPING) {
2691 /* A mummy wrapping absorbs it and protects you */
2693 You_feel("rather itchy under %s.", yname(uarmc));
2695 You("%s
\82Ì
\89º
\82ª
\83\80\83Y
\83\80\83Y
\82µ
\82½
\81D", xname(uarmc));
2698 if (ordinary || !rn2(10)) { /* permanent */
2699 HInvis |= FROMOUTSIDE;
2700 } else { /* temporary */
2701 incr_itimeout(&HInvis, d(obj->spe, 250));
2706 self_invis_message();
2711 case WAN_SPEED_MONSTER:
2712 if (!(HFast & INTRINSIC)) {
2718 You("
\93®
\82«
\82ª
\91¬
\82
\82È
\82Á
\82½
\81D");
2721 Your("quickness feels more natural.");
2723 You("
\91¬
\82³
\82É
\8aµ
\82ê
\82Ä
\82«
\82½
\81D");
2724 exercise(A_DEX, TRUE);
2726 HFast |= FROMOUTSIDE;
2732 if (Sleep_resistance) {
2733 shieldeff(u.ux, u.uy);
2735 You("don't feel sleepy!");
2737 You("
\96°
\82
\82È
\82ç
\82È
\82¢
\81I");
2740 pline_The("sleep ray hits you!");
2742 pline("
\96°
\82è
\8cõ
\90ü
\82ª
\82 \82È
\82½
\82É
\96½
\92\86\82µ
\82½
\81I");
2743 fall_asleep(-rnd(50), TRUE);
2747 case WAN_SLOW_MONSTER:
2748 case SPE_SLOW_MONSTER:
2749 if (HFast & (TIMEOUT | INTRINSIC)) {
2755 case WAN_TELEPORTATION:
2756 case SPE_TELEPORT_AWAY:
2758 /* same criteria as when mounted (zap_steed) */
2759 if ((Teleport_control && !Stunned) || !couldsee(u.ux0, u.uy0)
2760 || distu(u.ux0, u.uy0) >= 16)
2765 case SPE_FINGER_OF_DEATH:
2766 if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
2767 pline((obj->otyp == WAN_DEATH)
2769 ? "The wand shoots an apparently harmless beam at you."
2771 ? "
\8fñ
\82Ì
\8cõ
\90ü
\82Í
\82Ç
\82¤
\82â
\82ç
\82 \82È
\82½
\82É
\89e
\8b¿
\82ð
\97^
\82¦
\82È
\82¢
\82à
\82Ì
\82Ì
\82æ
\82¤
\82¾
\81D"
2773 : "You seem no deader than before.");
2775 : "
\82 \82È
\82½
\82Í
\82±
\82ê
\88È
\8fã
\8e\80\82Ë
\82È
\82¢
\82æ
\82¤
\82¾
\81D");
2780 Sprintf(killer.name, "shot %sself with a death ray", uhim());
2781 killer.format = NO_KILLER_PREFIX;
2783 Strcpy(killer.name, "
\8e©
\95ª
\82ª
\8c\82\82Á
\82½
\8e\80\82Ì
\8cõ
\90ü
\82É
\82æ
\82Á
\82Ä");
2784 killer.format = KILLED_BY;
2787 You("irradiate yourself with pure energy!");
2789 You("
\83G
\83l
\83\8b\83M
\81[
\82ð
\8e©
\95ª
\8e©
\90g
\82É
\8fÆ
\8eË
\82µ
\82½
\81D");
2793 pline("
\82 \82È
\82½
\82Í
\8e\80\82É
\82Ü
\82µ
\82½
\81D");
2794 /* They might survive with an amulet of life saving */
2797 case WAN_UNDEAD_TURNING:
2798 case SPE_TURN_UNDEAD:
2800 (void) unturn_dead(&youmonst);
2801 if (is_undead(youmonst.data)) {
2803 You_feel("frightened and %sstunned.",
2804 Stunned ? "even more " : "");
2806 You("
\8b°
\95|
\82µ%s
\82
\82ç
\82
\82ç
\82µ
\82½
\81D",
2807 Stunned ? "
\82³
\82ç
\82É" : "");
2809 make_stunned((HStun & TIMEOUT) + (long) rnd(30), FALSE);
2812 You("shudder in dread.");
2814 You("
\8b°
\95|
\82Å
\90k
\82¦
\82½
\81D");
2817 case SPE_EXTRA_HEALING:
2818 learn_it = TRUE; /* (no effect for spells...) */
2819 healup(d(6, obj->otyp == SPE_EXTRA_HEALING ? 8 : 4), 0, FALSE,
2820 (obj->blessed || obj->otyp == SPE_EXTRA_HEALING));
2822 You_feel("%sbetter.", obj->otyp == SPE_EXTRA_HEALING ? "much " : "");
2824 You("%s
\8bC
\95ª
\82ª
\82æ
\82
\82È
\82Á
\82½
\81D", obj->otyp == SPE_EXTRA_HEALING ? "
\82Æ
\82Ä
\82à" : "");
2826 case WAN_LIGHT: /* (broken wand) */
2827 /* assert( !ordinary ); */
2828 damage = d(obj->spe, 25);
2830 case EXPENSIVE_CAMERA:
2833 damage = lightdamage(obj, ordinary, damage);
2835 if (flashburn((long) damage))
2837 damage = 0; /* reset */
2845 /* invent is hit iff hero doesn't escape from a trap */
2846 if (!u.utrap || !openholdingtrap(&youmonst, &learn_it)) {
2848 boolean boxing = FALSE;
2850 /* unlock carried boxes */
2851 for (otmp = invent; otmp; otmp = otmp->nobj)
2853 (void) boxlock(otmp, obj);
2857 update_inventory(); /* in case any box->lknown has changed */
2859 /* trigger previously escaped trapdoor */
2860 (void) openfallingtrap(&youmonst, TRUE, &learn_it);
2864 case SPE_WIZARD_LOCK:
2865 /* similar logic to opening; invent is hit iff no trap triggered */
2866 if (u.utrap || !closeholdingtrap(&youmonst, &learn_it)) {
2868 boolean boxing = FALSE;
2870 /* lock carried boxes */
2871 for (otmp = invent; otmp; otmp = otmp->nobj)
2873 (void) boxlock(otmp, obj);
2877 update_inventory(); /* in case any box->lknown has changed */
2882 case SPE_DETECT_UNSEEN:
2888 for (otmp = invent; otmp; otmp = otmp->nobj) {
2890 if (Is_container(otmp) || otmp->otyp == STATUE) {
2892 if (!SchroedingersBox(otmp))
2901 case SPE_STONE_TO_FLESH: {
2902 struct obj *otmp, *onxt;
2905 if (u.umonnum == PM_STONE_GOLEM) {
2907 (void) polymon(PM_FLESH_GOLEM);
2911 fix_petrification(); /* saved! */
2913 /* but at a cost.. */
2914 for (otmp = invent; otmp; otmp = onxt) {
2916 if (bhito(otmp, obj))
2920 * It is possible that we can now merge some inventory.
2921 * Do a highly paranoid merge. Restart from the beginning
2926 for (otmp = invent; !didmerge && otmp; otmp = otmp->nobj)
2927 for (onxt = otmp->nobj; onxt; onxt = onxt->nobj)
2928 if (merged(&otmp, &onxt)) {
2936 impossible("zapyourself: object %d used?", obj->otyp);
2939 /* if effect was observable then discover the wand type provided
2940 that the wand itself has been seen */
2946 /* called when poly'd hero uses breath attack against self */
2949 struct attack *mattk;
2951 int dtyp = 20 + mattk->adtyp - 1; /* breath by hero */
2952 const char *fltxt = flash_types[dtyp]; /* blast of <something> */
2954 zhitu(dtyp, mattk->damn, fltxt, u.ux, u.uy);
2957 /* light damages hero in gremlin form */
2959 lightdamage(obj, ordinary, amt)
2960 struct obj *obj; /* item making light (fake book if spell) */
2961 boolean ordinary; /* wand/camera zap vs wand destruction */
2962 int amt; /* pseudo-damage used to determine blindness duration */
2968 if (dmg && youmonst.data == &mons[PM_GREMLIN]) {
2969 /* reduce high values (from destruction of wand with many charges) */
2972 dmg = 10 + rnd(dmg - 10);
2976 pline("Ow, that light hurts%c", (dmg > 2 || u.mh <= 5) ? '!' : '.');
2978 pline("
\82¨
\82í
\81C
\8cõ
\82ª
\92É
\82¢%s", (dmg > 2 || u.mh <= 5) ? "
\81I" : "
\81D");
2979 /* [composing killer/reason is superfluous here; if fatal, cause
2980 of death will always be "killed while stuck in creature form"] */
2982 if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS)
2983 ordinary = FALSE; /* say blasted rather than zapped */
2985 how = (obj->oclass != SPBOOK_CLASS)
2986 ? (const char *) ansimpleoname(obj)
2990 : "
\8cõ
\82Ì
\96\82\96@";
2992 Sprintf(buf, "%s %sself with %s", ordinary ? "zapped" : "blasted",
2995 Sprintf(buf, "
\8e©
\95ª
\82Å%s
\82ð
\97\81\82Ñ
\82Ä", how);
2997 /* might rehumanize(); could be fatal, but only for Unchanging */
2999 losehp(Maybe_Half_Phys(dmg), buf, NO_KILLER_PREFIX);
3001 losehp(Maybe_Half_Phys(dmg), buf, KILLED_BY);
3007 /* light[ning] causes blindness */
3012 if (!resists_blnd(&youmonst)) {
3013 You(are_blinded_by_the_flash);
3014 make_blinded(duration, FALSE);
3016 Your1(vision_clears);
3022 /* you've zapped a wand downwards while riding
3023 * Return TRUE if the steed was hit by the wand.
3024 * Return FALSE if the steed was not hit by the wand.
3028 struct obj *obj; /* wand or spell */
3030 int steedhit = FALSE;
3032 bhitpos.x = u.usteed->mx, bhitpos.y = u.usteed->my;
3034 switch (obj->otyp) {
3036 * Wands that are allowed to hit the steed
3037 * Carefully test the results of any that are
3038 * moved here from the bottom section.
3041 probe_monster(u.usteed);
3045 case WAN_TELEPORTATION:
3046 case SPE_TELEPORT_AWAY:
3047 /* you go together */
3049 /* same criteria as when unmounted (zapyourself) */
3050 if ((Teleport_control && !Stunned) || !couldsee(u.ux0, u.uy0)
3051 || distu(u.ux0, u.uy0) >= 16)
3056 /* Default processing via bhitm() for these */
3057 case SPE_CURE_SICKNESS:
3058 case WAN_MAKE_INVISIBLE:
3059 case WAN_CANCELLATION:
3060 case SPE_CANCELLATION:
3064 case SPE_FORCE_BOLT:
3065 case WAN_SLOW_MONSTER:
3066 case SPE_SLOW_MONSTER:
3067 case WAN_SPEED_MONSTER:
3069 case SPE_EXTRA_HEALING:
3070 case SPE_DRAIN_LIFE:
3073 (void) bhitm(u.usteed, obj);
3085 * cancel a monster (possibly the hero). inventory is cancelled only
3086 * if the monster is zapping itself directly, since otherwise the
3087 * effect is too strong. currently non-hero monsters do not zap
3088 * themselves with cancellation.
3091 cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel)
3092 register struct monst *mdef;
3093 register struct obj *obj;
3094 boolean youattack, allow_cancel_kill, self_cancel;
3096 boolean youdefend = (mdef == &youmonst);
3097 static const char writing_vanishes[] =
3099 "Some writing vanishes from %s head!";
3101 "
\89½
\82©
\82Ì
\95¶
\8e\9a\82ª%s
\82Ì
\93ª
\82©
\82ç
\8fÁ
\82¦
\82½
\81I";
3103 static const char your[] = "your"; /* should be extern */
3105 static const char your[] = "
\82 \82È
\82½"; /* should be extern */
3108 if (youdefend ? (!youattack && Antimagic)
3109 : resist(mdef, obj->oclass, 0, NOTELL))
3110 return FALSE; /* resisted cancellation */
3112 if (self_cancel) { /* 1st cancel inventory */
3115 for (otmp = (youdefend ? invent : mdef->minvent); otmp;
3119 context.botl = 1; /* potential AC change */
3124 /* now handle special cases */
3126 if (Upolyd) { /* includes lycanthrope in creature form */
3128 * Return to normal form unless Unchanging.
3129 * Hero in clay golem form dies if Unchanging.
3130 * Does not cure lycanthropy or stop timed random polymorph.
3132 if (u.umonnum == PM_CLAY_GOLEM) {
3134 pline(writing_vanishes, your);
3135 else /* note: "dark" rather than "heavy" is intentional... */
3137 You_feel("%s headed.", Hallucination ? "dark" : "light");
3138 #else /*
\82¢
\82¢
\96ó
\8cê
\82ð
\8ev
\82¢
\82Â
\82©
\82È
\82¢
\82Ì
\82Å
\8c¶
\8ao
\82Å
\83\81\83b
\83Z
\81[
\83W
\82ð
\95Ï
\82¦
\82È
\82¢ */
3139 You_feel("
\8cy
\82Í
\82¸
\82Ý
\82¾
\82Á
\82½
\8bC
\82ª
\82µ
\82½
\81D");
3141 u.mh = 0; /* fatal; death handled by rehumanize() */
3143 if (Unchanging && u.mh > 0)
3145 Your("amulet grows hot for a moment, then cools.");
3147 Your("
\96\82\8f\9c\82¯
\82Í
\82µ
\82Î
\82ç
\82
\94M
\82
\82È
\82è
\81C
\82â
\82ª
\82Ä
\8c³
\82É
\96ß
\82Á
\82½
\81D");
3153 /* force shapeshifter into its base form */
3154 if (M_AP_TYPE(mdef) != M_AP_NOTHING)
3156 /* [not 'else if'; chameleon might have been hiding as a mimic] */
3157 if (mdef->cham >= LOW_PM) {
3158 /* note: newcham() uncancels shapechangers (resets m->mcan
3159 to 0), but only for shapechangers whose m->cham is already
3160 NON_PM and we just verified that it's LOW_PM or higher */
3161 newcham(mdef, &mons[mdef->cham], FALSE, FALSE);
3162 mdef->cham = NON_PM; /* cancelled shapeshifter can't shift */
3164 if (is_were(mdef->data) && !is_human(mdef->data))
3167 if (mdef->data == &mons[PM_CLAY_GOLEM]) {
3168 if (canseemon(mdef))
3170 pline(writing_vanishes, s_suffix(mon_nam(mdef)));
3172 pline(writing_vanishes, mon_nam(mdef));
3174 /* !allow_cancel_kill is for Magicbane, where clay golem
3175 will be killed somewhere back up the call/return chain... */
3176 if (allow_cancel_kill) {
3180 monkilled(mdef, "", AD_SPEL);
3187 /* you've zapped an immediate type wand up or down */
3190 struct obj *obj; /* wand or spell */
3192 boolean striking = FALSE, disclose = FALSE;
3193 int x, y, xx, yy, ptmp;
3199 /* some wands have special effects other than normal bhitpile */
3200 /* drawbridge might change <u.ux,u.uy> */
3201 x = xx = u.ux; /* <x,y> is zap location */
3202 y = yy = u.uy; /* <xx,yy> is drawbridge (portcullis) position */
3203 ttmp = t_at(x, y); /* trap if there is one */
3205 switch (obj->otyp) {
3210 You("probe towards the %s.", ceiling(x, y));
3212 You("
\8fã
\95û
\82Ì%s
\82ð
\92²
\82×
\82½
\81D", ceiling(x,y));
3214 ptmp += bhitpile(obj, bhito, x, y, u.dz);
3216 You("probe beneath the %s.", surface(x, y));
3218 You("
\89º
\95û
\82Ì%s
\82ð
\92²
\82×
\82½
\81D", surface(x,y));
3219 ptmp += display_binventory(x, y, TRUE);
3223 Your("probe reveals nothing.");
3225 pline("
\92²
\8d¸
\82Ì
\8c\8b\89Ê
\89½
\82à
\82Å
\82Ä
\82±
\82È
\82©
\82Á
\82½
\81D");
3226 return TRUE; /* we've done our own bhitpile */
3229 /* up or down, but at closed portcullis only */
3230 if (is_db_wall(x, y) && find_drawbridge(&xx, &yy)) {
3231 open_drawbridge(xx, yy);
3233 } else if (u.dz > 0 && (x == xdnstair && y == ydnstair)
3234 /* can't use the stairs down to quest level 2 until
3235 leader "unlocks" them; give feedback if you try */
3236 && on_level(&u.uz, &qstart_level) && !ok_to_quest()) {
3238 pline_The("stairs seem to ripple momentarily.");
3240 pline("
\8aK
\92i
\82ª
\88ê
\8fu
\97h
\82ê
\82½
\82æ
\82¤
\82É
\8c©
\82¦
\82½
\81D");
3243 /* down will release you from bear trap or web */
3244 if (u.dz > 0 && u.utrap) {
3245 (void) openholdingtrap(&youmonst, &disclose);
3246 /* down will trigger trapdoor, hole, or [spiked-] pit */
3247 } else if (u.dz > 0 && !u.utrap) {
3248 (void) openfallingtrap(&youmonst, FALSE, &disclose);
3252 case SPE_FORCE_BOLT:
3256 case SPE_WIZARD_LOCK:
3257 /* down at open bridge or up or down at open portcullis */
3258 if (((levl[x][y].typ == DRAWBRIDGE_DOWN)
3260 : (is_drawbridge_wall(x, y) >= 0 && !is_db_wall(x, y)))
3261 && find_drawbridge(&xx, &yy)) {
3263 close_drawbridge(xx, yy);
3265 destroy_drawbridge(xx, yy);
3267 } else if (striking && u.dz < 0 && rn2(3) && !Is_airlevel(&u.uz)
3268 && !Is_waterlevel(&u.uz) && !Underwater
3269 && !Is_qstart(&u.uz)) {
3271 /* similar to zap_dig() */
3273 pline("A rock is dislodged from the %s and falls on your %s.",
3274 ceiling(x, y), body_part(HEAD));
3276 pline("%s
\82©
\82ç
\8aâ
\82ª
\97\8e\82¿
\82Ä
\82 \82È
\82½
\82Ì%s
\82É
\96½
\92\86\82µ
\82½
\81D",
3277 ceiling(x, y), body_part(HEAD));
3279 dmg = rnd((uarmh && is_metallic(uarmh)) ? 2 : 6);
3281 losehp(Maybe_Half_Phys(dmg), "falling rock", KILLED_BY_AN);
3283 losehp(Maybe_Half_Phys(dmg), "
\97\8e\8aâ
\82Å", KILLED_BY_AN);
3284 if ((otmp = mksobj_at(ROCK, x, y, FALSE, FALSE)) != 0) {
3285 (void) xname(otmp); /* set dknown, maybe bknown */
3289 } else if (u.dz > 0 && ttmp) {
3290 if (!striking && closeholdingtrap(&youmonst, &disclose)) {
3291 ; /* now stuck in web or bear trap */
3292 } else if (striking && ttmp->ttyp == TRAPDOOR) {
3293 /* striking transforms trapdoor into hole */
3294 if (Blind && !ttmp->tseen) {
3296 pline("%s beneath you shatters.", Something);
3298 pline("
\82 \82È
\82½
\82Ì
\89º
\82É
\82 \82é
\89½
\82©
\82ª
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D");
3299 } else if (!ttmp->tseen) { /* => !Blind */
3301 pline("There's a trapdoor beneath you; it shatters.");
3303 pline("
\82 \82È
\82½
\82Ì
\89º
\82É
\82Í
\97\8e\82µ
\94à
\82ª
\82 \82Á
\82½
\81G
\82»
\82ê
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D");
3306 pline("The trapdoor beneath you shatters.");
3308 pline("
\82 \82È
\82½
\82Ì
\89º
\82É
\82 \82é
\97\8e\82µ
\94à
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D");
3314 /* might fall down hole */
3316 } else if (!striking && ttmp->ttyp == HOLE) {
3317 /* locking transforms hole into trapdoor */
3318 ttmp->ttyp = TRAPDOOR;
3319 if (Blind || !ttmp->tseen) {
3321 pline("Some %s swirls beneath you.",
3322 is_ice(x, y) ? "frost" : "dust");
3324 pline("
\82 \82È
\82½
\82Ì
\89º
\82Å%s
\82ª
\82¤
\82¸
\82ð
\8aª
\82
\82Ì
\82ª
\8c©
\82¦
\82½
\81D",
3325 is_ice(x,y) ? "
\91\9a" : "
\82Ù
\82±
\82è");
3331 pline("A trapdoor appears beneath you.");
3333 pline("
\82 \82È
\82½
\82Ì
\89º
\82É
\97\8e\82µ
\94à
\82ª
\82 \82ç
\82í
\82ê
\82½
\81D");
3336 /* hadn't fallen down hole; won't fall now */
3340 case SPE_STONE_TO_FLESH:
3341 if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || Underwater
3342 || (Is_qstart(&u.uz) && u.dz < 0)) {
3343 pline1(nothing_happens);
3344 } else if (u.dz < 0) { /* we should do more... */
3346 pline("Blood drips on your %s.", body_part(FACE));
3348 pline("
\8c\8c\82ª
\82 \82È
\82½
\82Ì%s
\82Ö
\82µ
\82½
\82½
\82è
\97\8e\82¿
\82Ä
\82«
\82½
\81D", body_part(FACE));
3349 } else if (u.dz > 0 && !OBJ_AT(u.ux, u.uy)) {
3351 Print this message only if there wasn't an engraving
3352 affected here. If water or ice, act like waterlevel case.
3354 e = engr_at(u.ux, u.uy);
3355 if (!(e && e->engr_type == ENGRAVE)) {
3356 if (is_pool(u.ux, u.uy) || is_ice(u.ux, u.uy))
3357 pline1(nothing_happens);
3360 pline("Blood %ss %s your %s.",
3361 is_lava(u.ux, u.uy) ? "boil" : "pool",
3362 Levitation ? "beneath" : "at",
3363 makeplural(body_part(FOOT)));
3366 makeplural(body_part(FOOT)),
3367 Levitation ? "
\82Ì
\89º" : "
\8c³",
3368 is_lava(u.ux, u.uy) ?
3369 "
\82Å
\8c\8c\82ª
\95¦
\93«
\82µ
\82½" : "
\82É
\8c\8c\82¾
\82Ü
\82è
\82ª
\8fo
\97\88\82½");
3379 /* zapping downward */
3380 (void) bhitpile(obj, bhito, x, y, u.dz);
3382 /* subset of engraving effects; none sets `disclose' */
3383 if ((e = engr_at(x, y)) != 0 && e->engr_type != HEADSTONE) {
3384 switch (obj->otyp) {
3388 make_engr_at(x, y, random_engraving(buf), moves, (xchar) 0);
3390 case WAN_CANCELLATION:
3391 case SPE_CANCELLATION:
3392 case WAN_MAKE_INVISIBLE:
3395 case WAN_TELEPORTATION:
3396 case SPE_TELEPORT_AWAY:
3399 case SPE_STONE_TO_FLESH:
3400 if (e->engr_type == ENGRAVE) {
3401 /* only affects things in stone */
3403 pline_The(Hallucination
3404 ? "floor runs like butter!"
3405 : "edges on the floor get smoother.");
3408 ? "
\8f°
\82ª
\83o
\83^
\81[
\82Ì
\82æ
\82¤
\82É
\91\96\82Á
\82Ä
\82¢
\82Á
\82½
\81I"
3409 : "
\8f°
\82Ì
\89\8f\82ª
\82È
\82ß
\82ç
\82©
\82É
\82È
\82Á
\82½
\81D");
3411 wipe_engr_at(x, y, d(2, 4), TRUE);
3415 case SPE_FORCE_BOLT:
3416 wipe_engr_at(x, y, d(2, 4), TRUE);
3422 } else if (u.dz < 0) {
3423 /* zapping upward */
3425 /* game flavor: if you're hiding under "something"
3426 * a zap upward should hit that "something".
3428 if (u.uundetected && hides_under(youmonst.data)) {
3430 otmp = level.objects[u.ux][u.uy];
3433 hitit = bhito(otmp, obj);
3435 (void) hideunder(&youmonst);
3444 /* used by do_break_wand() was well as by weffects() */
3454 /* if do_osshock() set obj_zapped while polying, give a message now */
3457 You_feel("shuddering vibrations.");
3459 You("
\82¼
\82Á
\82Æ
\82·
\82é
\90U
\93®
\82ð
\8a´
\82¶
\82½
\81D");
3463 /* called for various wand and spell effects - M. Stephenson */
3468 int otyp = obj->otyp;
3469 boolean disclose = FALSE, was_unkn = !objects[otyp].oc_name_known;
3471 exercise(A_WIS, TRUE);
3472 if (u.usteed && (objects[otyp].oc_dir != NODIR) && !u.dx && !u.dy
3473 && (u.dz > 0) && zap_steed(obj)) {
3475 } else if (objects[otyp].oc_dir == IMMEDIATE) {
3476 zapsetup(); /* reset obj_zapped */
3478 (void) bhitm(u.ustuck, obj);
3479 /* [how about `bhitpile(u.ustuck->minvent)' effect?] */
3481 disclose = zap_updown(obj);
3483 (void) bhit(u.dx, u.dy, rn1(8, 6), ZAPPED_WAND, bhitm, bhito,
3486 zapwrapup(); /* give feedback for obj_zapped */
3488 } else if (objects[otyp].oc_dir == NODIR) {
3492 /* neither immediate nor directionless */
3494 if (otyp == WAN_DIGGING || otyp == SPE_DIG)
3496 else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH)
3497 buzz(otyp - SPE_MAGIC_MISSILE + 10, u.ulevel / 2 + 1, u.ux, u.uy,
3499 else if (otyp >= WAN_MAGIC_MISSILE && otyp <= WAN_LIGHTNING)
3500 buzz(otyp - WAN_MAGIC_MISSILE,
3501 (otyp == WAN_MAGIC_MISSILE) ? 2 : 6, u.ux, u.uy, u.dx, u.dy);
3503 impossible("weffects: unexpected spell or wand");
3509 more_experienced(0, 10);
3514 /* augment damage for a spell dased on the hero's intelligence (and level) */
3516 spell_damage_bonus(dmg)
3517 int dmg; /* base amount to be adjusted by bonus or penalty */
3519 int intell = ACURR(A_INT);
3521 /* Punish low intelligence before low level else low intelligence
3522 gets punished only when high level */
3524 /* -3 penalty, but never reduce combined amount below 1
3525 (if dmg is 0 for some reason, we're careful to leave it there) */
3527 dmg = (dmg <= 3) ? 1 : dmg - 3;
3528 } else if (intell <= 13 || u.ulevel < 5)
3529 ; /* no bonus or penalty; dmg remains same */
3530 else if (intell <= 18)
3532 else if (intell <= 24 || u.ulevel < 14)
3535 dmg += 3; /* Int 25 */
3541 * Generate the to hit bonus for a spell. Based on the hero's skill in
3542 * spell class and dexterity.
3545 spell_hit_bonus(skill)
3549 int dex = ACURR(A_DEX);
3551 switch (P_SKILL(spell_skilltype(skill))) {
3552 case P_ISRESTRICTED:
3574 /* Will change when print stuff below removed */
3577 /* Even increment for dextrous heroes (see weapon.c abon) */
3578 hit_bon += dex - 14;
3587 /* force == 0 occurs e.g. with sleep ray */
3588 /* note that large force is usual with wands so that !! would
3589 require information about hand/weapon/wand */
3591 return (const char *) ((force < 0) ? "?" : (force <= 4) ? "." : "!");
3593 return (const char *) ((force < 0) ? "
\81H" : (force <= 4) ? "
\81D" : "
\81I");
3597 hit(str, mtmp, force)
3600 const char *force; /* usually either "." or "!" */
3602 if ((!cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)
3603 && !(u.uswallow && mtmp == u.ustuck)) || !flags.verbose)
3605 pline("%s %s it.", The(str), vtense(str, "hit"));
3607 pline("%s
\82Í
\89½
\82©
\82É
\96½
\92\86\82µ
\82½
\81D", str);
3610 pline("%s %s %s%s", The(str), vtense(str, "hit"),
3611 mon_nam(mtmp), force);
3613 pline("%s
\82Í%s
\82É
\96½
\92\86\82µ
\82½%s", str,
3614 mon_nam(mtmp), force);
3620 register const char *str;
3621 register struct monst *mtmp;
3625 "%s %s %s.", The(str), vtense(str, "miss"),
3626 ((cansee(bhitpos.x, bhitpos.y) || canspotmon(mtmp)) && flags.verbose)
3631 "%s
\82Ì%s
\82Ö
\82Ì
\8dU
\8c\82\82Í
\82Í
\82¸
\82ê
\82½
\81D", str,
3632 ((cansee(bhitpos.x,bhitpos.y) || canspotmon(mtmp)) && flags.verbose)
3639 skiprange(range, skipstart, skipend)
3640 int range, *skipstart, *skipend;
3642 int tr = (range / 4);
3643 int tmp = range - ((tr > 0) ? rnd(tr) : 0);
3646 *skipend = tmp - ((tmp / 4) * rnd(3));
3647 if (*skipend >= tmp)
3652 * Called for the following distance effects:
3653 * when a weapon is thrown (weapon == THROWN_WEAPON)
3654 * when an object is kicked (KICKED_WEAPON)
3655 * when an IMMEDIATE wand is zapped (ZAPPED_WAND)
3656 * when a light beam is flashed (FLASHED_LIGHT)
3657 * when a mirror is applied (INVIS_BEAM)
3658 * A thrown/kicked object falls down at end of its range or when a monster
3659 * is hit. The variable 'bhitpos' is set to the final position of the weapon
3660 * thrown/zapped. The ray of a wand may affect (by calling a provided
3661 * function) several objects and monsters on its path. The return value
3662 * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer.
3664 * Thrown and kicked objects (THROWN_WEAPON or KICKED_WEAPON) may be
3665 * destroyed and *pobj set to NULL to indicate this.
3667 * Check !u.uswallow before calling bhit().
3668 * This function reveals the absence of a remembered invisible monster in
3669 * necessary cases (throwing or kicking weapons). The presence of a real
3670 * one is revealed for a weapon, but if not a weapon is left up to fhitm().
3673 bhit(ddx, ddy, range, weapon, fhitm, fhito, pobj)
3674 register int ddx, ddy, range; /* direction and range */
3675 enum bhit_call_types weapon; /* defined in hack.h */
3676 int FDECL((*fhitm), (MONST_P, OBJ_P)), /* fns called when mon/obj hit */
3677 FDECL((*fhito), (OBJ_P, OBJ_P));
3678 struct obj **pobj; /* object tossed/used, set to NULL
3679 * if object is destroyed */
3681 struct monst *mtmp, *result = (struct monst *) 0;
3682 struct obj *obj = *pobj;
3684 boolean shopdoor = FALSE, point_blank = TRUE;
3685 boolean in_skip = FALSE, allow_skip = FALSE;
3686 boolean tethered_weapon = FALSE;
3687 int skiprange_start = 0, skiprange_end = 0, skipcount = 0;
3689 if (weapon == KICKED_WEAPON) {
3690 /* object starts one square in front of player */
3691 bhitpos.x = u.ux + ddx;
3692 bhitpos.y = u.uy + ddy;
3699 if (weapon == THROWN_WEAPON && obj && obj->otyp == ROCK) {
3700 skiprange(range, &skiprange_start, &skiprange_end);
3701 allow_skip = !rn2(3);
3704 if (weapon == FLASHED_LIGHT) {
3705 tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam));
3706 } else if (weapon == THROWN_TETHERED_WEAPON && obj) {
3707 tethered_weapon = TRUE;
3708 weapon = THROWN_WEAPON; /* simplify 'if's that follow below */
3709 tmp_at(DISP_TETHER, obj_to_glyph(obj, rn2_on_display_rng));
3710 } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM)
3711 tmp_at(DISP_FLASH, obj_to_glyph(obj, rn2_on_display_rng));
3713 while (range-- > 0) {
3727 if (is_pick(obj) && inside_shop(x, y)
3728 && (mtmp = shkcatch(obj, x, y)) != 0) {
3729 tmp_at(DISP_END, 0);
3734 typ = levl[bhitpos.x][bhitpos.y].typ;
3736 /* iron bars will block anything big enough and break some things */
3737 if (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) {
3739 && hits_bars(pobj, x - ddx, y - ddy, bhitpos.x, bhitpos.y,
3740 point_blank ? 0 : !rn2(5), 1)) {
3741 /* caveat: obj might now be null... */
3746 } else if (obj->lamplit && !Blind) {
3747 show_transient_light(obj, bhitpos.x, bhitpos.y);
3751 if (weapon == ZAPPED_WAND && find_drawbridge(&x, &y)) {
3752 boolean learn_it = FALSE;
3754 switch (obj->otyp) {
3757 if (is_db_wall(bhitpos.x, bhitpos.y)) {
3758 if (cansee(x, y) || cansee(bhitpos.x, bhitpos.y))
3760 open_drawbridge(x, y);
3764 case SPE_WIZARD_LOCK:
3765 if ((cansee(x, y) || cansee(bhitpos.x, bhitpos.y))
3766 && levl[x][y].typ == DRAWBRIDGE_DOWN)
3768 close_drawbridge(x, y);
3771 case SPE_FORCE_BOLT:
3772 if (typ != DRAWBRIDGE_UP)
3773 destroy_drawbridge(x, y);
3781 mtmp = m_at(bhitpos.x, bhitpos.y);
3786 * skiprange_start is only set if this is a thrown rock
3788 if (skiprange_start && (range == skiprange_start) && allow_skip) {
3789 if (is_pool(bhitpos.x, bhitpos.y) && !mtmp) {
3793 pline("%s %s%s.", Yname2(obj), otense(obj, "skip"),
3794 skipcount ? " again" : "");
3796 pline("%s
\82Í%s
\92µ
\82Ë
\82½
\81D", Yname2(obj),
3797 skipcount ? "
\8dÄ
\82Ñ" : "");
3801 You_hear("%s skip.", yname(obj));
3803 You_hear("%s
\82ª
\92µ
\82Ë
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D", yname(obj));
3805 } else if (skiprange_start > skiprange_end + 1) {
3810 if (range <= skiprange_end) {
3812 if (range > 3) /* another bounce? */
3813 skiprange(range, &skiprange_start, &skiprange_end);
3814 } else if (mtmp && M_IN_WATER(mtmp->data)) {
3815 if (!Blind && canspotmon(mtmp))
3817 pline("%s %s over %s.", Yname2(obj), otense(obj, "pass"),
3820 pline("%s
\82Í%s
\82ð
\94ò
\82Ñ
\89z
\82¦
\82½
\81D", Yname2(obj),
3823 mtmp = (struct monst *) 0;
3827 /* if mtmp is a shade and missile passes harmlessly through it,
3828 give message and skip it in order to keep going */
3829 if (mtmp && (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
3830 && shade_miss(&youmonst, mtmp, obj, TRUE, TRUE))
3831 mtmp = (struct monst *) 0;
3834 notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
3835 if (weapon == FLASHED_LIGHT) {
3836 /* FLASHED_LIGHT hitting invisible monster should
3837 pass through instead of stop so we call
3838 flash_hits_mon() directly rather than returning
3839 mtmp back to caller. That allows the flash to
3840 keep on going. Note that we use mtmp->minvis
3841 not canspotmon() because it makes no difference
3842 whether the hero can see the monster or not. */
3844 obj->ox = u.ux, obj->oy = u.uy;
3845 (void) flash_hits_mon(mtmp, obj);
3847 tmp_at(DISP_END, 0);
3848 result = mtmp; /* caller will call flash_hits_mon */
3851 } else if (weapon == INVIS_BEAM) {
3852 /* Like FLASHED_LIGHT, INVIS_BEAM should continue
3853 through invisible targets; unlike it, we aren't
3854 prepared for multiple hits so just get first one
3855 that's either visible or could see its invisible
3856 self. [No tmp_at() cleanup is needed here.] */
3857 if (!mtmp->minvis || perceives(mtmp->data)) {
3861 } else if (weapon != ZAPPED_WAND) {
3863 /* THROWN_WEAPON, KICKED_WEAPON */
3864 if (!tethered_weapon)
3865 tmp_at(DISP_END, 0);
3867 if (cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp))
3868 map_invisible(bhitpos.x, bhitpos.y);
3873 (*fhitm)(mtmp, obj);
3877 if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING
3878 && glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) {
3879 unmap_object(bhitpos.x, bhitpos.y);
3884 if (bhitpile(obj, fhito, bhitpos.x, bhitpos.y, 0))
3887 if (weapon == KICKED_WEAPON
3888 && ((obj->oclass == COIN_CLASS
3889 && OBJ_AT(bhitpos.x, bhitpos.y))
3890 || ship_object(obj, bhitpos.x, bhitpos.y,
3891 costly_spot(bhitpos.x, bhitpos.y)))) {
3892 tmp_at(DISP_END, 0);
3893 goto bhit_done; /* result == (struct monst *) 0 */
3896 if (weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) {
3897 switch (obj->otyp) {
3902 case SPE_WIZARD_LOCK:
3903 case SPE_FORCE_BOLT:
3904 if (doorlock(obj, bhitpos.x, bhitpos.y)) {
3905 if (cansee(bhitpos.x, bhitpos.y)
3906 || (obj->otyp == WAN_STRIKING && !Deaf))
3908 if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN
3909 && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) {
3911 add_damage(bhitpos.x, bhitpos.y, SHOP_DOOR_COST);
3917 if (!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) {
3922 if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) {
3923 /* 'I' present but no monster: erase */
3924 /* do this before the tmp_at() */
3925 if (glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)
3927 unmap_object(bhitpos.x, bhitpos.y);
3930 tmp_at(bhitpos.x, bhitpos.y);
3932 /* kicked objects fall in pools */
3933 if ((weapon == KICKED_WEAPON)
3934 && (is_pool(bhitpos.x, bhitpos.y)
3935 || is_lava(bhitpos.x, bhitpos.y)))
3937 if (IS_SINK(typ) && weapon != FLASHED_LIGHT)
3938 break; /* physical objects fall onto sink */
3940 /* limit range of ball so hero won't make an invalid move */
3941 if (weapon == THROWN_WEAPON && range > 0
3942 && obj->otyp == HEAVY_IRON_BALL) {
3946 if ((bobj = sobj_at(BOULDER, x, y)) != 0) {
3949 pline("%s hits %s.", The(distant_name(obj, xname)),
3952 pline("%s
\82Í%s
\82É
\96½
\92\86\82µ
\82½
\81D", distant_name(obj, xname),
3956 } else if (obj == uball) {
3957 if (!test_move(x - ddx, y - ddy, ddx, ddy, TEST_MOVE)) {
3958 /* nb: it didn't hit anything directly */
3961 pline("%s jerks to an abrupt halt.",
3962 The(distant_name(obj, xname))); /* lame */
3964 pline("%s
\82Í
\82Æ
\82Â
\82º
\82ñ
\83K
\83N
\83\93\82Æ
\8e~
\82Ü
\82Á
\82½
\81D",
3965 distant_name(obj, xname)); /* lame */
3968 } else if (Sokoban && (t = t_at(x, y)) != 0
3969 && (is_pit(t->ttyp) || is_hole(t->ttyp))) {
3970 /* hero falls into the trap, so ball stops */
3976 /* thrown/kicked missile has moved away from its starting spot */
3977 point_blank = FALSE; /* affects passing through iron bars */
3980 if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM && !tethered_weapon)
3981 tmp_at(DISP_END, 0);
3985 pay_for_damage("destroy", FALSE);
3987 pay_for_damage("
\94j
\89ó
\82·
\82é", FALSE);
3990 if (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
3991 transient_light_cleanup();
3996 /* process thrown boomerang, which travels a curving path...
3997 * A multi-shot volley ought to have all missiles in flight at once,
3998 * but we're called separately for each one. We terminate the volley
3999 * early on a failed catch since continuing to throw after being hit
4000 * is too obviously silly.
4003 boomhit(obj, dx, dy)
4008 int boom; /* showsym[] index */
4010 boolean counterclockwise = TRUE; /* right-handed throw */
4012 /* counterclockwise traversal patterns:
4013 * ..........................54.................................
4014 * ..................43.....6..3....765.........................
4015 * ..........32.....5..2...7...2...8...4....87..................
4016 * .........4..1....6..1...8..1....9...3...9..6.....98..........
4017 * ..21@....5...@...7..@....9@......@12....@...5...@..7.....@9..
4018 * .3...9....6..9....89.....................1..4...1..6....1..8.
4019 * .4...8.....78.............................23....2..5...2...7.
4020 * ..567............................................34....3..6..
4021 * ........................................................45...
4022 * (invert rows for corresponding clockwise patterns)
4027 boom = counterclockwise ? S_boomleft : S_boomright;
4028 for (i = 0; i < 8; i++)
4029 if (xdir[i] == dx && ydir[i] == dy)
4031 tmp_at(DISP_FLASH, cmap_to_glyph(boom));
4032 for (ct = 0; ct < 10; ct++) {
4033 i = (i + 8) % 8; /* 0..7 (8 -> 0, -1 -> 7) */
4034 boom = (S_boomleft + S_boomright - boom); /* toggle */
4035 tmp_at(DISP_CHANGE, cmap_to_glyph(boom)); /* change glyph */
4040 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
4042 tmp_at(DISP_END, 0);
4045 if (!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ)
4046 || closed_door(bhitpos.x, bhitpos.y)) {
4051 if (bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
4052 if (Fumbling || rn2(20) >= ACURR(A_DEX)) {
4053 /* we hit ourselves */
4054 (void) thitu(10 + obj->spe, dmgval(obj, &youmonst), &obj,
4058 "
\83u
\81[
\83\81\83\89\83\93");
4061 } else { /* we catch it */
4062 tmp_at(DISP_END, 0);
4064 You("skillfully catch the boomerang.");
4066 You("
\8fã
\8eè
\82É
\83u
\81[
\83\81\83\89\83\93\82ð
\92Í
\82Ü
\82¦
\82½
\81D");
4070 tmp_at(bhitpos.x, bhitpos.y);
4072 if (IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) {
4077 pline("
\83J
\83\89\83\93\81I");
4078 break; /* boomerang falls on sink */
4080 /* ct==0, initial position, we want next delta to be same;
4081 ct==5, opposite position, repeat delta undoes first one */
4083 i += (counterclockwise ? -1 : 1);
4085 tmp_at(DISP_END, 0); /* do not leave last symbol */
4086 return (struct monst *) 0;
4089 /* used by buzz(); also used by munslime(muse.c); returns damage applied
4090 to mon; note: caller is responsible for killing mon if damage is fatal */
4092 zhitm(mon, type, nd, ootmp)
4093 register struct monst *mon;
4094 register int type, nd;
4095 struct obj **ootmp; /* to return worn armor for caller to disintegrate */
4097 register int tmp = 0;
4098 register int abstype = abs(type) % 10;
4099 boolean sho_shieldeff = FALSE;
4100 boolean spellcaster = is_hero_spell(type); /* maybe get a bonus! */
4102 *ootmp = (struct obj *) 0;
4104 case ZT_MAGIC_MISSILE:
4105 if (resists_magm(mon)) {
4106 sho_shieldeff = TRUE;
4111 tmp = spell_damage_bonus(tmp);
4114 if (resists_fire(mon)) {
4115 sho_shieldeff = TRUE;
4119 if (resists_cold(mon))
4122 tmp = spell_damage_bonus(tmp);
4123 if (burnarmor(mon)) {
4125 (void) destroy_mitem(mon, POTION_CLASS, AD_FIRE);
4127 (void) destroy_mitem(mon, SCROLL_CLASS, AD_FIRE);
4129 (void) destroy_mitem(mon, SPBOOK_CLASS, AD_FIRE);
4130 destroy_mitem(mon, FOOD_CLASS, AD_FIRE); /* carried slime */
4134 if (resists_cold(mon)) {
4135 sho_shieldeff = TRUE;
4139 if (resists_fire(mon))
4142 tmp = spell_damage_bonus(tmp);
4144 (void) destroy_mitem(mon, POTION_CLASS, AD_COLD);
4148 (void) sleep_monst(mon, d(nd, 25),
4149 type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0');
4151 case ZT_DEATH: /* death/disintegration */
4152 if (abs(type) != ZT_BREATH(ZT_DEATH)) { /* death */
4153 if (mon->data == &mons[PM_DEATH]) {
4154 mon->mhpmax += mon->mhpmax / 2;
4155 if (mon->mhpmax >= MAGIC_COOKIE)
4156 mon->mhpmax = MAGIC_COOKIE - 1;
4157 mon->mhp = mon->mhpmax;
4161 if (nonliving(mon->data) || is_demon(mon->data)
4162 || is_vampshifter(mon) || resists_magm(mon)) {
4163 /* similar to player */
4164 sho_shieldeff = TRUE;
4167 type = -1; /* so they don't get saving throws */
4171 if (resists_disint(mon)) {
4172 sho_shieldeff = TRUE;
4173 } else if (mon->misc_worn_check & W_ARMS) {
4174 /* destroy shield; victim survives */
4175 *ootmp = which_armor(mon, W_ARMS);
4176 } else if (mon->misc_worn_check & W_ARM) {
4177 /* destroy body armor, also cloak if present */
4178 *ootmp = which_armor(mon, W_ARM);
4179 if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
4180 m_useup(mon, otmp2);
4182 /* no body armor, victim dies; destroy cloak
4183 and shirt now in case target gets life-saved */
4185 if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
4186 m_useup(mon, otmp2);
4187 if ((otmp2 = which_armor(mon, W_ARMU)) != 0)
4188 m_useup(mon, otmp2);
4190 type = -1; /* no saving throw wanted */
4191 break; /* not ordinary damage */
4196 if (resists_elec(mon)) {
4197 sho_shieldeff = TRUE;
4199 /* can still blind the monster */
4203 tmp = spell_damage_bonus(tmp);
4204 if (!resists_blnd(mon)
4205 && !(type > 0 && u.uswallow && mon == u.ustuck)) {
4206 register unsigned rnd_tmp = rnd(50);
4208 if ((mon->mblinded + rnd_tmp) > 127)
4209 mon->mblinded = 127;
4211 mon->mblinded += rnd_tmp;
4214 (void) destroy_mitem(mon, WAND_CLASS, AD_ELEC);
4215 /* not actually possible yet */
4217 (void) destroy_mitem(mon, RING_CLASS, AD_ELEC);
4220 if (resists_poison(mon)) {
4221 sho_shieldeff = TRUE;
4227 if (resists_acid(mon)) {
4228 sho_shieldeff = TRUE;
4233 acid_damage(MON_WEP(mon));
4235 erode_armor(mon, ERODE_CORRODE);
4239 shieldeff(mon->mx, mon->my);
4240 if (is_hero_spell(type) && (Role_if(PM_KNIGHT) && u.uhave.questart))
4242 if (tmp > 0 && type >= 0
4243 && resist(mon, type < ZT_SPELL(0) ? WAND_CLASS : '\0', 0, NOTELL))
4246 tmp = 0; /* don't allow negative damage */
4247 debugpline3("zapped monster hp = %d (= %d - %d)", mon->mhp - tmp,
4254 zhitu(type, nd, fltxt, sx, sy)
4259 int dam = 0, abstyp = abs(type);
4263 Sprintf(buf, "%s
\82É
\82æ
\82Á
\82Ä", fltxt);
4267 switch (abstyp % 10) {
4268 case ZT_MAGIC_MISSILE:
4272 pline_The("missiles bounce off!");
4274 pline("
\96\82\96@
\82Ì
\96î
\82Í
\94½
\8eË
\82µ
\82½
\81I");
4277 exercise(A_STR, FALSE);
4281 if (Fire_resistance) {
4284 You("don't feel hot!");
4286 You("
\94M
\82³
\82ð
\8a´
\82¶
\82È
\82¢
\81I");
4287 ugolemeffects(AD_FIRE, d(nd, 6));
4292 if (burnarmor(&youmonst)) { /* "body hit" */
4294 destroy_item(POTION_CLASS, AD_FIRE);
4296 destroy_item(SCROLL_CLASS, AD_FIRE);
4298 destroy_item(SPBOOK_CLASS, AD_FIRE);
4299 destroy_item(FOOD_CLASS, AD_FIRE);
4303 if (Cold_resistance) {
4306 You("don't feel cold.");
4308 You("
\97â
\82½
\82³
\82ð
\8a´
\82¶
\82È
\82¢
\81D");
4309 ugolemeffects(AD_COLD, d(nd, 6));
4314 destroy_item(POTION_CLASS, AD_COLD);
4317 if (Sleep_resistance) {
4318 shieldeff(u.ux, u.uy);
4320 You("don't feel sleepy.");
4322 You("
\96°
\82
\82È
\82ç
\82È
\82¢
\81D");
4324 fall_asleep(-d(nd, 25), TRUE); /* sleep ray */
4328 if (abstyp == ZT_BREATH(ZT_DEATH)) {
4329 if (Disint_resistance) {
4331 You("are not disintegrated.");
4333 You("
\95ª
\89ð
\82³
\82ê
\82È
\82¢
\81D");
4336 /* destroy shield; other possessions are safe */
4337 (void) destroy_arm(uarms);
4340 /* destroy suit; if present, cloak goes too */
4342 (void) destroy_arm(uarmc);
4343 (void) destroy_arm(uarm);
4346 /* no shield or suit, you're dead; wipe out cloak
4347 and/or shirt in case of life-saving or bones */
4349 (void) destroy_arm(uarmc);
4351 (void) destroy_arm(uarmu);
4352 } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
4355 You("seem unaffected.");
4357 You("
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\82æ
\82¤
\82¾
\81D");
4359 } else if (Antimagic) {
4362 You("aren't affected.");
4364 You("
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\81D");
4367 killer.format = KILLED_BY_AN;
4368 Strcpy(killer.name, fltxt ? fltxt : "");
4369 /* when killed by disintegration breath, don't leave corpse */
4370 u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM;
4372 return; /* lifesaved */
4374 if (Shock_resistance) {
4377 You("aren't affected.");
4379 You("
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\81D");
4380 ugolemeffects(AD_ELEC, d(nd, 6));
4383 exercise(A_CON, FALSE);
4386 destroy_item(WAND_CLASS, AD_ELEC);
4388 destroy_item(RING_CLASS, AD_ELEC);
4392 poisoned("blast", A_DEX, "poisoned blast", 15, FALSE);
4394 poisoned("
\91§", A_DEX, "
\93Å
\82Ì
\91§", 15, FALSE);
4397 if (Acid_resistance) {
4399 pline_The("%s doesn't hurt.", hliquid("acid"));
4401 pline_The("%s
\82Å
\82Í
\8f\9d\82Â
\82©
\82È
\82©
\82Á
\82½
\81D", hliquid("
\8e_"));
4405 pline_The("%s burns!", hliquid("acid"));
4407 pline_The("%s
\82Å
\8fÄ
\82¯
\82½
\81I", hliquid("
\8e_"));
4409 exercise(A_STR, FALSE);
4411 /* using two weapons at once makes both of them more vulnerable */
4412 if (!rn2(u.twoweap ? 3 : 6))
4414 if (u.twoweap && !rn2(3))
4415 acid_damage(uswapwep);
4417 erode_armor(&youmonst, ERODE_CORRODE);
4421 /* Half_spell_damage protection yields half-damage for wands & spells,
4422 including hero's own ricochets; breath attacks do full damage */
4423 if (dam && Half_spell_damage && !(abstyp >= 20 && abstyp <= 29))
4424 dam = (dam + 1) / 2;
4425 losehp(dam, fltxt, KILLED_BY_AN);
4430 * burn objects (such as scrolls and spellbooks) on floor
4431 * at position x,y; return the number of objects burned
4434 burn_floor_objects(x, y, give_feedback, u_caused)
4436 boolean give_feedback; /* caller needs to decide about visibility checks */
4439 struct obj *obj, *obj2;
4440 long i, scrquan, delquan;
4441 char buf1[BUFSZ], buf2[BUFSZ];
4444 for (obj = level.objects[x][y]; obj; obj = obj2) {
4445 obj2 = obj->nexthere;
4446 if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS
4447 || (obj->oclass == FOOD_CLASS
4448 && obj->otyp == GLOB_OF_GREEN_SLIME)) {
4449 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL
4450 || obj_resists(obj, 2, 100))
4452 scrquan = obj->quan; /* number present */
4453 delquan = 0L; /* number to destroy */
4454 for (i = scrquan; i > 0L; i--)
4458 /* save name before potential delobj() */
4459 if (give_feedback) {
4461 Strcpy(buf1, (x == u.ux && y == u.uy)
4463 : distant_name(obj, xname));
4465 Strcpy(buf2, (x == u.ux && y == u.uy)
4467 : distant_name(obj, xname));
4468 obj->quan = scrquan;
4470 /* useupf(), which charges, only if hero caused damage */
4472 useupf(obj, delquan);
4473 else if (delquan < scrquan)
4474 obj->quan -= delquan;
4478 if (give_feedback) {
4481 pline("%ld %s burn.", delquan, buf2);
4483 pline("%ld%s
\82Ì%s
\82ª
\94R
\82¦
\82½
\81D",
4485 obj->oclass == SCROLL_CLASS ? "
\96\87" : "
\8dû",
4490 pline("%s burns.", An(buf1));
4492 pline("%s
\82Í
\94R
\82¦
\82½
\81D", buf1);
4500 /* will zap/spell/breath attack score a hit against armor class `ac'? */
4504 int type; /* either hero cast spell type or 0 */
4506 int chance = rn2(20);
4507 int spell_bonus = type ? spell_hit_bonus(type) : 0;
4509 /* small chance for naked target to avoid being hit */
4511 return rnd(10) < ac + spell_bonus;
4513 /* very high armor protection does not achieve invulnerability */
4516 return (3 - chance < ac + spell_bonus);
4520 disintegrate_mon(mon, type, fltxt)
4522 int type; /* hero vs other */
4525 struct obj *otmp, *otmp2, *m_amulet = mlifesaver(mon);
4527 if (canseemon(mon)) {
4530 pline("%s is disintegrated!", Monnam(mon));
4532 pline("%s
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81I", Monnam(mon));
4535 hit(fltxt, mon, "!");
4537 hit(fltxt, mon, "
\81I");
4540 /* note: worn amulet of life saving must be preserved in order to operate */
4541 #define oresist_disintegration(obj) \
4542 (objects[obj->otyp].oc_oprop == DISINT_RES || obj_resists(obj, 5, 50) \
4543 || is_quest_artifact(obj) || obj == m_amulet)
4545 for (otmp = mon->minvent; otmp; otmp = otmp2) {
4547 if (!oresist_disintegration(otmp)) {
4548 if (otmp->owornmask) {
4549 /* in case monster's life gets saved */
4550 mon->misc_worn_check &= ~otmp->owornmask;
4551 if (otmp->owornmask & W_WEP)
4552 setmnotwielded(mon, otmp);
4553 /* also dismounts hero if this object is steed's saddle */
4554 update_mon_intrinsics(mon, otmp, FALSE, TRUE);
4555 otmp->owornmask = 0L;
4557 obj_extract_self(otmp);
4558 obfree(otmp, (struct obj *) 0);
4562 #undef oresist_disintegration
4565 monkilled(mon, (char *) 0, -AD_RBRE);
4567 xkilled(mon, XKILL_NOMSG | XKILL_NOCORPSE);
4571 buzz(type, nd, sx, sy, dx, dy)
4576 dobuzz(type, nd, sx, sy, dx, dy, TRUE);
4580 * type == 0 to 9 : you shooting a wand
4581 * type == 10 to 19 : you casting a spell
4582 * type == 20 to 29 : you breathing as a monster
4583 * type == -10 to -19 : monster casting spell
4584 * type == -20 to -29 : monster breathing at you
4585 * type == -30 to -39 : monster shooting a wand
4586 * called with dx = dy = 0 with vertical bolts
4589 dobuzz(type, nd, sx, sy, dx, dy, say)
4590 register int type, nd;
4591 register xchar sx, sy;
4592 register int dx, dy;
4593 boolean say; /* Announce out of sight hit/miss events if true */
4595 int range, abstype = abs(type) % 10;
4596 register xchar lsx, lsy;
4599 boolean shopdamage = FALSE;
4604 /* if its a Hero Spell then get its SPE_TYPE */
4605 spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0;
4607 fltxt = flash_types[(type <= -30) ? abstype : abs(type)];
4613 tmp = zhitm(u.ustuck, type, nd, &otmp);
4618 pline("%s rips into %s%s", The(fltxt), mon_nam(u.ustuck),
4621 pline("%s
\82Í%s
\82ð
\82Ð
\82«
\82³
\82¢
\82½%s", fltxt, mon_nam(u.ustuck),
4624 /* Using disintegration from the inside only makes a hole... */
4625 if (tmp == MAGIC_COOKIE)
4627 if (DEADMONSTER(u.ustuck))
4634 if (dx == 0 && dy == 0)
4636 save_bhitpos = bhitpos;
4638 tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype));
4639 while (range-- > 0) {
4644 if (!isok(sx, sy) || levl[sx][sy].typ == STONE)
4648 if (cansee(sx, sy)) {
4649 /* reveal/unreveal invisible monsters before tmp_at() */
4650 if (mon && !canspotmon(mon))
4651 map_invisible(sx, sy);
4653 (void) unmap_invisible(sx, sy);
4654 if (ZAP_POS(levl[sx][sy].typ)
4655 || (isok(lsx, lsy) && cansee(lsx, lsy)))
4657 delay_output(); /* wait a little */
4660 /* hit() and miss() need bhitpos to match the target */
4661 bhitpos.x = sx, bhitpos.y = sy;
4662 /* Fireballs only damage when they explode */
4663 if (type != ZT_SPELL(ZT_FIRE)) {
4664 range += zap_over_floor(sx, sy, type, &shopdamage, 0);
4665 /* zap with fire -> melt ice -> drown monster, so monster
4666 found and cached above might not be here any more */
4671 if (type == ZT_SPELL(ZT_FIRE))
4674 mon->mstrategy &= ~STRAT_WAITMASK;
4676 notonhead = (mon->mx != bhitpos.x || mon->my != bhitpos.y);
4677 if (zap_hit(find_mac(mon), spell_type)) {
4678 if (mon_reflects(mon, (char *) 0)) {
4679 if (cansee(mon->mx, mon->my)) {
4680 hit(fltxt, mon, exclam(0));
4681 shieldeff(mon->mx, mon->my);
4683 (void) mon_reflects(mon,
4684 "But it reflects from %s %s!");
4686 (void) mon_reflects(mon,
4687 "
\82µ
\82©
\82µ
\82»
\82ê
\82Í%s
\82Ì%s
\82Å
\94½
\8eË
\82µ
\82½
\81I");
4693 boolean mon_could_move = mon->mcanmove;
4694 int tmp = zhitm(mon, type, nd, &otmp);
4696 if (is_rider(mon->data)
4697 && abs(type) == ZT_BREATH(ZT_DEATH)) {
4698 if (canseemon(mon)) {
4700 hit(fltxt, mon, ".");
4702 hit(fltxt, mon, "
\81D");
4704 pline("%s disintegrates.", Monnam(mon));
4706 pline("%s
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D", Monnam(mon));
4708 pline("%s body reintegrates before your %s!",
4709 s_suffix(Monnam(mon)),
4710 (eyecount(youmonst.data) == 1)
4712 : makeplural(body_part(EYE)));
4714 pline("%s
\82Ì
\91Ì
\82Í
\82 \82È
\82½
\82Ì
\96Ú
\82Ì
\91O
\82Å
\8dÄ
\8c\8b\8d\87\82µ
\82½
\81I",
4718 pline("%s resurrects!", Monnam(mon));
4720 pline("%s
\82Í
\91h
\82Á
\82½
\81I", Monnam(mon));
4722 mon->mhp = mon->mhpmax;
4723 break; /* Out of while loop */
4725 if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) {
4726 if (canseemon(mon)) {
4728 hit(fltxt, mon, ".");
4730 hit(fltxt, mon, "
\81D");
4732 pline("%s absorbs the deadly %s!", Monnam(mon),
4733 type == ZT_BREATH(ZT_DEATH) ? "blast"
4736 pline("%s
\82Í
\8e\80\82Ì%s
\82ð
\8bz
\8eû
\82µ
\82½
\81I", Monnam(mon),
4737 type == ZT_BREATH(ZT_DEATH) ? "
\91§"
4741 pline("It seems even stronger than before.");
4743 pline("
\82³
\82ç
\82É
\8b
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82³
\82¦
\82·
\82é
\81D");
4745 break; /* Out of while loop */
4748 if (tmp == MAGIC_COOKIE) { /* disintegration */
4749 disintegrate_mon(mon, type, fltxt);
4750 } else if (DEADMONSTER(mon)) {
4752 /* mon has just been killed by another monster */
4753 monkilled(mon, fltxt, AD_RBRE);
4755 int xkflags = XKILL_GIVEMSG; /* killed(mon); */
4757 /* killed by hero; we know 'type' isn't negative;
4758 if it's fire, highly flammable monsters leave
4759 no corpse; don't bother reporting that they
4760 "burn completely" -- unnecessary verbosity */
4761 if ((type % 10 == ZT_FIRE)
4762 /* paper golem or straw golem */
4763 && completelyburns(mon->data))
4764 xkflags |= XKILL_NOCORPSE;
4765 xkilled(mon, xkflags);
4769 /* normal non-fatal hit */
4770 if (say || canseemon(mon))
4771 hit(fltxt, mon, exclam(tmp));
4773 /* some armor was destroyed; no damage done */
4776 pline("%s %s is disintegrated!",
4777 s_suffix(Monnam(mon)),
4778 distant_name(otmp, xname));
4780 pline("%s
\82Ì%s
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81I",
4782 distant_name(otmp, xname));
4786 if (mon_could_move && !mon->mcanmove) /* ZT_SLEEP */
4792 if (say || canseemon(mon))
4795 } else if (sx == u.ux && sy == u.uy && range >= 0) {
4797 if (u.usteed && !rn2(3) && !mon_reflects(u.usteed, (char *) 0)) {
4800 } else if (zap_hit((int) u.uac, 0)) {
4803 pline("%s hits you!", The(fltxt));
4805 pline("%s
\82Í
\82 \82È
\82½
\82É
\96½
\92\86\82µ
\82½
\81I", fltxt);
4809 (void) ureflects("But %s reflects from your %s!",
4812 (void) ureflects("
\82µ
\82©
\82µ
\81C%s
\82Í
\82 \82È
\82½
\82Ì%s
\82É
\82æ
\82Á
\82Ä
\94½
\8eË
\82µ
\82½
\81D",
4817 pline("For some reason you are not affected.");
4819 pline("
\82È
\82º
\82©
\82 \82È
\82½
\82Í
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82©
\82Á
\82½
\81D");
4824 zhitu(type, nd, fltxt, sx, sy);
4826 } else if (!Blind) {
4828 pline("%s whizzes by you!", The(fltxt));
4830 pline("%s
\82Í
\82 \82È
\82½
\82Ì
\82»
\82Î
\82ð
\82©
\82·
\82ß
\82½
\81I", fltxt);
4831 } else if (abstype == ZT_LIGHTNING) {
4833 Your("%s tingles.", body_part(ARM));
4835 Your("%s
\82Í
\83q
\83\8a\83q
\83\8a\82µ
\82½
\81D", body_part(ARM));
4837 if (abstype == ZT_LIGHTNING)
4838 (void) flashburn((long) d(nd, 50));
4843 if (!ZAP_POS(levl[sx][sy].typ)
4844 || (closed_door(sx, sy) && range >= 0)) {
4845 int bounce, bchance;
4850 bchance = (levl[sx][sy].typ == STONE) ? 10
4851 : (In_mines(&u.uz) && IS_WALL(levl[sx][sy].typ)) ? 20
4854 fireball = (type == ZT_SPELL(ZT_FIRE));
4855 if ((--range > 0 && isok(lsx, lsy) && cansee(lsx, lsy))
4857 if (Is_airlevel(&u.uz)) { /* nothing to bounce off of */
4859 pline_The("%s vanishes into the aether!", fltxt);
4861 pline_The("%s
\82Í
\83G
\81[
\83e
\83\8b\8bó
\8aÔ
\82É
\8fÁ
\82¦
\82½
\81I", fltxt);
4863 type = ZT_WAND(ZT_FIRE); /* skip pending fireball */
4865 } else if (fireball) {
4868 break; /* fireballs explode before the obstacle */
4871 pline_The("%s bounces!", fltxt);
4873 pline_The("%s
\82Í
\94½
\8eË
\82µ
\82½
\81I", fltxt);
4875 if (!dx || !dy || !rn2(bchance)) {
4879 if (isok(sx, lsy) && ZAP_POS(rmn = levl[sx][lsy].typ)
4880 && !closed_door(sx, lsy)
4881 && (IS_ROOM(rmn) || (isok(sx + dx, lsy)
4882 && ZAP_POS(levl[sx + dx][lsy].typ))))
4884 if (isok(lsx, sy) && ZAP_POS(rmn = levl[lsx][sy].typ)
4885 && !closed_door(lsx, sy)
4886 && (IS_ROOM(rmn) || (isok(lsx, sy + dy)
4887 && ZAP_POS(levl[lsx][sy + dy].typ))))
4888 if (!bounce || rn2(2))
4902 tmp_at(DISP_CHANGE, zapdir_to_glyph(dx, dy, abstype));
4906 tmp_at(DISP_END, 0);
4907 if (type == ZT_SPELL(ZT_FIRE))
4908 explode(sx, sy, type, d(12, 6), 0, EXPL_FIERY);
4911 pay_for_damage(abstype == ZT_FIRE
4913 : abstype == ZT_COLD
4915 /* "damage" indicates wall rather than door */
4916 : abstype == ZT_ACID
4918 : abstype == ZT_DEATH
4923 pay_for_damage(abstype == ZT_FIRE
4925 : abstype == ZT_COLD
4926 ? "
\95²
\81X
\82É
\82·
\82é"
4927 : abstype == ZT_ACID
4928 ? "
\8f\9d\82Â
\82¯
\82é"
4929 : abstype == ZT_DEATH
4930 ? "
\95²
\8dÓ
\82·
\82é"
4931 : "
\94j
\89ó
\82·
\82é",
4934 bhitpos = save_bhitpos;
4942 struct rm *lev = &levl[x][y];
4948 msg = "The ice crackles and melts.";
4950 msg = "
\95X
\82Í
\83s
\83L
\83s
\83L
\96Â
\82è
\81C
\97n
\82¯
\82½
\81D";
4951 if (lev->typ == DRAWBRIDGE_UP || lev->typ == DRAWBRIDGE_DOWN) {
4952 lev->drawbridgemask &= ~DB_ICE; /* revert to DB_MOAT */
4953 } else { /* lev->typ == ICE */
4955 if (lev->icedpool == ICED_POOL)
4960 lev->typ = (lev->icedpool == ICED_POOL ? POOL : MOAT);
4964 spot_stop_timers(x, y, MELT_ICE_AWAY); /* no more ice to melt away */
4965 obj_ice_effects(x, y, FALSE);
4972 if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
4975 pline("%s settles...", An(xname(otmp)));
4977 pline("%s
\82Í
\82Í
\82Ü
\82Á
\82½
\81D
\81D
\81D", xname(otmp));
4979 obj_extract_self(otmp); /* boulder isn't being pushed */
4980 if (!boulder_hits_pool(otmp, x, y, FALSE))
4981 impossible("melt_ice: no pool?");
4982 /* try again if there's another boulder and pool didn't fill */
4983 } while (is_pool(x, y) && (otmp = sobj_at(BOULDER, x, y)) != 0);
4986 if (x == u.ux && y == u.uy)
4987 spoteffects(TRUE); /* possibly drown, notice objects */
4988 else if (is_pool(x, y) && (mtmp = m_at(x, y)) != 0)
4989 (void) minliquid(mtmp);
4992 #define MIN_ICE_TIME 50
4993 #define MAX_ICE_TIME 2000
4995 * Usually start a melt_ice timer; sometimes the ice will become
4996 * permanent instead.
4999 start_melt_ice_timeout(x, y, min_time)
5001 long min_time; /* <x,y>'s old melt timeout (deleted by time we get here) */
5006 when = (int) min_time;
5007 if (when < MIN_ICE_TIME - 1)
5008 when = MIN_ICE_TIME - 1;
5010 /* random timeout; surrounding ice locations ought to be a factor... */
5011 while (++when <= MAX_ICE_TIME)
5012 if (!rn2((MAX_ICE_TIME - when) + MIN_ICE_TIME))
5015 /* if we're within MAX_ICE_TIME, install a melt timer;
5016 otherwise, omit it to leave this ice permanent */
5017 if (when <= MAX_ICE_TIME) {
5018 where = ((long) x << 16) | (long) y;
5019 (void) start_timer((long) when, TIMER_LEVEL, MELT_ICE_AWAY,
5020 long_to_any(where));
5027 * Called when ice has melted completely away.
5030 melt_ice_away(arg, timeout)
5032 long timeout UNUSED;
5035 long where = arg->a_long;
5036 boolean save_mon_moving = context.mon_moving; /* will be False */
5038 /* melt_ice -> minliquid -> mondead|xkilled shouldn't credit/blame hero */
5039 context.mon_moving = TRUE; /* hero isn't causing this ice to melt */
5040 y = (xchar) (where & 0xFFFF);
5041 x = (xchar) ((where >> 16) & 0xFFFF);
5042 /* melt_ice does newsym when appropriate */
5044 melt_ice(x, y, "Some ice melts away.");
5046 melt_ice(x, y, "
\95X
\82ª
\8f
\82µ
\97n
\82¯
\82½
\81D");
5047 context.mon_moving = save_mon_moving;
5050 /* Burn floor scrolls, evaporate pools, etc... in a single square.
5051 * Used both for normal bolts of fire, cold, etc... and for fireballs.
5052 * Sets shopdamage to TRUE if a shop door is destroyed, and returns the
5053 * amount by which range is reduced (the latter is just ignored by fireballs)
5056 zap_over_floor(x, y, type, shopdamage, exploding_wand_typ)
5059 boolean *shopdamage;
5060 short exploding_wand_typ;
5062 const char *zapverb;
5065 struct rm *lev = &levl[x][y];
5066 boolean see_it = cansee(x, y), yourzap;
5067 int rangemod = 0, abstype = abs(type) % 10;
5072 if (t && t->ttyp == WEB) {
5073 /* a burning web is too flimsy to notice if you can't see it */
5076 Norep("A web bursts into flames!");
5078 Norep("
\82
\82à
\82Ì
\91\83\82Í
\89\8a\82É
\95ï
\82Ü
\82ê
\82½
\81I");
5079 (void) delfloortrap(t);
5084 melt_ice(x, y, (char *) 0);
5085 } else if (is_pool(x, y)) {
5087 const char *msgtxt = (!Deaf)
5088 ? "You hear hissing gas." /* Deaf-aware */
5090 ? "That seemed remarkably uneventful."
5093 const char *msgtxt = (!Deaf)
5094 ? "
\82µ
\82ã
\81[
\82Á
\82Æ
\82¢
\82¤
\83K
\83X
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D" /* Deaf-aware */
5096 ? "
\82±
\82ê
\82Í
\8bÁ
\82
\82Ù
\82Ç
\82È
\82ñ
\82Å
\82à
\82È
\82³
\82»
\82¤
\82¾
\81D"
5100 if (lev->typ != POOL) { /* MOAT or DRAWBRIDGE_UP */
5103 msgtxt = "Some water evaporates.";
5105 msgtxt = "
\82·
\82±
\82µ
\90\85\82ª
\8fö
\94
\82µ
\82½
\81D";
5108 lev->typ = ROOM, lev->flags = 0;
5109 t = maketrap(x, y, PIT);
5114 msgtxt = "The water evaporates.";
5116 msgtxt = "
\90\85\82ª
\8fö
\94
\82µ
\82½
\81D";
5119 Norep("%s", msgtxt);
5120 if (lev->typ == ROOM)
5122 } else if (IS_FOUNTAIN(lev->typ)) {
5125 pline("Steam billows from the fountain.");
5127 pline("
\90ò
\82©
\82ç
\8fö
\8bC
\82ª
\97§
\82¿
\82Ì
\82Ú
\82Á
\82½
\81D");
5129 dryup(x, y, type > 0);
5131 break; /* ZT_FIRE */
5134 if (is_pool(x, y) || is_lava(x, y)) {
5135 boolean lava = is_lava(x, y),
5136 moat = is_moat(x, y);
5138 if (lev->typ == WATER) {
5139 /* For now, don't let WATER freeze. */
5142 pline_The("%s freezes for a moment.", hliquid("water"));
5144 pline_The("%s
\82Í
\88ê
\8fu
\93\80\82Á
\82½
\81D", hliquid("
\90\85"));
5147 You_hear("a soft crackling.");
5149 You_hear("
\83s
\83L
\81I
\82Æ
\82¢
\82¤
\89¹
\82ð
\95·
\82¢
\82½
\81D");
5150 rangemod -= 1000; /* stop */
5154 Strcpy(buf, waterbody_name(x, y)); /* for MOAT */
5156 if (lev->typ == DRAWBRIDGE_UP) {
5157 lev->drawbridgemask &= ~DB_UNDER; /* clear lava */
5158 lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE);
5160 lev->icedpool = lava ? 0
5161 : (lev->typ == POOL) ? ICED_POOL
5163 lev->typ = lava ? ROOM : ICE;
5169 Norep("The %s cools and solidifies.", hliquid("lava"));
5171 Norep("%s
\82Í
\97â
\82¦
\8cÅ
\82Ü
\82Á
\82½
\81D", hliquid("lava"));
5174 Norep("The %s is bridged with ice!", buf);
5176 Norep("%s
\82É
\95X
\82Ì
\8b´
\82ª
\82©
\82¯
\82ç
\82ê
\82½
\81I", buf);
5179 Norep("The %s freezes.", hliquid("water"));
5181 Norep("%s
\82Í
\93\80\82Á
\82½
\81D", hliquid("
\95X"));
5185 You_hear("a crackling sound.");
5187 You_hear("
\83s
\83L
\83s
\83L
\83b
\82Æ
\82¢
\82¤
\89¹
\82ð
\95·
\82¢
\82½
\81D");
5189 if (x == u.ux && y == u.uy) {
5190 if (u.uinwater) { /* not just `if (Underwater)' */
5191 /* leave the no longer existent water */
5195 vision_full_recalc = 1;
5196 } else if (u.utrap && u.utraptype == TT_LAVA) {
5199 You("pass through the now-solid rock.");
5201 You("
\82¢
\82Ü
\8cÅ
\82
\82È
\82Á
\82½
\82Î
\82©
\82è
\82Ì
\90Î
\82Ì
\92\86\82ð
\82·
\82è
\94²
\82¯
\82½
\81D");
5204 set_utrap(rn1(50, 20), TT_INFLOOR);
5206 You("are firmly stuck in the cooling rock.");
5208 You("
\97â
\82¦
\82½
\8aâ
\82Ì
\82È
\82©
\82É
\82µ
\82Á
\82©
\82è
\82Æ
\96\84\82Ü
\82Á
\82½
\81D");
5211 } else if ((mon = m_at(x, y)) != 0) {
5212 /* probably ought to do some hefty damage to any
5213 non-ice creature caught in freezing water;
5214 at a minimum, eels are forced out of hiding */
5215 if (is_swimmer(mon->data) && mon->mundetected) {
5216 mon->mundetected = 0;
5221 start_melt_ice_timeout(x, y, 0L);
5222 obj_ice_effects(x, y, TRUE);
5226 } else if (is_ice(x, y)) {
5229 /* Already ice here, so just firm it up. */
5230 /* Now ensure that only ice that is already timed is affected */
5231 if ((melt_time = spot_time_left(x, y, MELT_ICE_AWAY)) != 0L) {
5232 spot_stop_timers(x, y, MELT_ICE_AWAY);
5233 start_melt_ice_timeout(x, y, melt_time);
5236 break; /* ZT_COLD */
5239 (void) create_gas_cloud(x, y, 1, 8);
5243 if (lev->typ == IRONBARS) {
5244 if ((lev->wall_info & W_NONDIGGABLE) != 0) {
5247 Norep("The %s corrode somewhat but remain intact.",
5249 Norep("%s
\82Í
\8f
\82µ
\92É
\82ñ
\82¾
\82ª
\82Ü
\82¾
\82µ
\82Á
\82©
\82è
\82µ
\82Ä
\82¢
\82é
\81D",
5250 defsyms[S_bars].explanation);
5251 /* but nothing actually happens... */
5256 Norep("The %s melt.", defsyms[S_bars].explanation);
5258 Norep("%s
\82ª
\97n
\82¯
\82½
\81D", defsyms[S_bars].explanation);
5259 if (*in_rooms(x, y, SHOPBASE)) {
5260 /* in case we ever have a shop bounded by bars */
5261 lev->typ = ROOM, lev->flags = 0;
5264 add_damage(x, y, (type >= 0) ? SHOP_BARS_COST : 0L);
5268 lev->typ = DOOR, lev->doormask = D_NODOOR;
5274 break; /* ZT_ACID */
5280 /* set up zap text for possible door feedback; for exploding wand, we
5281 want "the blast" rather than "your blast" even if hero caused it */
5282 yourzap = (type >= 0 && !exploding_wand_typ);
5284 zapverb = "blast"; /* breath attack or wand explosion */
5286 zapverb = "
\8fÕ
\8c\82"; /* breath attack or wand explosion */
5288 if (!exploding_wand_typ) {
5289 if (abs(type) < ZT_SPELL(0))
5291 zapverb = "bolt"; /* wand zap */
5293 zapverb = "
\8cõ
\90ü"; /* wand zap */
5295 else if (abs(type) < ZT_BREATH(0))
5299 zapverb = "
\8eô
\95¶";
5302 /* secret door gets revealed, converted into regular door */
5303 if (levl[x][y].typ == SDOOR) {
5304 cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */
5305 /* target spot will now pass closed_door() test below
5306 (except on rogue level) */
5310 pline("%s %s reveals a secret door.",
5311 yourzap ? "Your" : "The", zapverb);
5313 pline("%s
\82Å
\89B
\82µ
\94à
\82ª
\96¾
\82ç
\82©
\82É
\82È
\82Á
\82½
\81D", zapverb);
5315 else if (Is_rogue_level(&u.uz))
5316 draft_message(FALSE); /* "You feel a draft." (open doorway) */
5319 /* regular door absorbs remaining zap range, possibly gets destroyed */
5320 if (closed_door(x, y)) {
5321 int new_doormask = -1;
5322 const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0;
5327 new_doormask = D_NODOOR;
5329 see_txt = "The door is consumed in flames!";
5331 see_txt = "
\94à
\82Í
\89\8a\82Å
\8fÄ
\82«
\82Â
\82
\82³
\82ê
\82½
\81I";
5333 sense_txt = "smell smoke.";
5335 sense_txt = "
\89\8c\82Ì
\93õ
\82¢
\82ª
\82µ
\82½
\81D";
5338 new_doormask = D_NODOOR;
5340 see_txt = "The door freezes and shatters!";
5342 see_txt = "
\94à
\82Í
\93\80\82è
\81C
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81I";
5344 sense_txt = "feel cold.";
5346 sense_txt = "
\97â
\8bC
\82ð
\8a´
\82¶
\82½
\81D";
5349 /* death spells/wands don't disintegrate */
5350 if (abs(type) != ZT_BREATH(ZT_DEATH))
5352 new_doormask = D_NODOOR;
5354 see_txt = "The door disintegrates!";
5356 see_txt = "
\94à
\82Í
\95²
\8dÓ
\82³
\82ê
\82½
\81I";
5358 hear_txt = "crashing wood.";
5360 hear_txt = "
\96Ø
\82Ì
\89ó
\82ê
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D";
5363 new_doormask = D_BROKEN;
5365 see_txt = "The door splinters!";
5367 see_txt = "
\94à
\82Í
\82¸
\82½
\82¸
\82½
\82É
\82È
\82Á
\82½
\81I";
5369 hear_txt = "crackling.";
5371 hear_txt = "
\83s
\83L
\83s
\83L
\82Æ
\82¢
\82¤
\89¹
\82ð
\95·
\82¢
\82½
\81D";
5375 if (exploding_wand_typ > 0) {
5376 /* Magical explosion from misc exploding wand */
5377 if (exploding_wand_typ == WAN_STRIKING) {
5378 new_doormask = D_BROKEN;
5380 see_txt = "The door crashes open!";
5382 see_txt = "
\94à
\82Í
\89ó
\82ê
\82Ä
\8aJ
\82¢
\82½
\81I";
5384 sense_txt = "feel a burst of cool air.";
5386 sense_txt = "
\97â
\8bC
\82Ì
\8f[
\96\9e\82ð
\8a´
\82¶
\82½
\81D";
5391 /* "the door absorbs the blast" would be
5392 inaccurate for an exploding wand since
5393 other adjacent locations still get hit */
5394 if (exploding_wand_typ)
5396 pline_The("door remains intact.");
5398 pline_The("
\94à
\82Í
\96³
\8f\9d\82¾
\81D");
5401 pline_The("door absorbs %s %s!", yourzap ? "your" : "the",
5404 pline_The("
\94à
\82Í%s%s
\82ð
\8bz
\8eû
\82µ
\82½
\81I", yourzap ? "
\82 \82È
\82½
\82ª
\95ú
\82Á
\82½" : "",
5409 You_feel("vibrations.");
5411 You("
\90U
\93®
\82ð
\8a´
\82¶
\82½
\81D");
5414 if (new_doormask >= 0) { /* door gets broken */
5415 if (*in_rooms(x, y, SHOPBASE)) {
5417 add_damage(x, y, SHOP_DOOR_COST);
5419 } else /* caused by monster */
5420 add_damage(x, y, 0L);
5422 lev->doormask = new_doormask;
5423 unblock_point(x, y); /* vision */
5427 } else if (sense_txt) {
5428 #if 0 /*JP*//*
\81u
\82 \82È
\82½
\82Í
\81v
\82ª
\95s
\93K
\90Ø
\82È
\95¶
\82à
\82 \82é*/
5433 } else if (hear_txt)
5434 You_hear1(hear_txt);
5435 if (picking_at(x, y)) {
5442 if (OBJ_AT(x, y) && abstype == ZT_FIRE)
5443 if (burn_floor_objects(x, y, FALSE, type > 0) && couldsee(x, y)) {
5446 You("%s of smoke.", !Blind ? "see a puff" : "smell a whiff");
5448 pline("%s
\81D", !Blind ? "
\82Û
\82í
\82Á
\82Æ
\89\8c\82ª
\82 \82ª
\82Á
\82½" : "
\89\8c\82Ì
\83v
\83\93\82Æ
\82¢
\82¤
\93õ
\82¢
\82ª
\82µ
\82½");
5450 if ((mon = m_at(x, y)) != 0) {
5453 setmangry(mon, TRUE);
5454 if (mon->ispriest && *in_rooms(mon->mx, mon->my, TEMPLE))
5456 if (mon->isshk && !*u.ushops)
5463 /* fractured by pick-axe or wand of striking */
5466 register struct obj *obj; /* no texts here! */
5469 boolean by_you = !context.mon_moving;
5471 if (by_you && get_obj_location(obj, &x, &y, 0) && costly_spot(x, y)) {
5472 struct monst *shkp = 0;
5473 char objroom = *in_rooms(x, y, SHOPBASE);
5475 if (billable(&shkp, obj, objroom, FALSE)) {
5476 /* shop message says "you owe <shk> <$> for it!" so we need
5477 to precede that with a message explaining what "it" is */
5479 You("fracture %s %s.", s_suffix(shkname(shkp)), xname(obj));
5481 You("%s
\82Ì%s
\82ð
\89ó
\82µ
\82½
\81D", shkname(shkp), xname(obj));
5482 breakobj(obj, x, y, TRUE, FALSE); /* charges for shop goods */
5485 if (by_you && obj->otyp == BOULDER)
5489 obj->oclass = GEM_CLASS;
5490 obj->quan = (long) rn1(60, 7);
5491 obj->owt = weight(obj);
5492 obj->dknown = obj->bknown = obj->rknown = 0;
5493 obj->known = objects[obj->otyp].oc_uses_known ? 0 : 1;
5494 dealloc_oextra(obj);
5496 if (obj->where == OBJ_FLOOR) {
5497 obj_extract_self(obj); /* move rocks back on top */
5498 place_object(obj, obj->ox, obj->oy);
5499 if (!does_block(obj->ox, obj->oy, &levl[obj->ox][obj->oy]))
5500 unblock_point(obj->ox, obj->oy);
5501 if (cansee(obj->ox, obj->oy))
5502 newsym(obj->ox, obj->oy);
5506 /* handle statue hit by striking/force bolt/pick-axe */
5509 register struct obj *obj;
5511 /* [obj is assumed to be on floor, so no get_obj_location() needed] */
5512 struct trap *trap = t_at(obj->ox, obj->oy);
5514 boolean by_you = !context.mon_moving;
5516 if (trap && trap->ttyp == STATUE_TRAP
5517 && activate_statue_trap(trap, obj->ox, obj->oy, TRUE))
5519 /* drop any objects contained inside the statue */
5520 while ((item = obj->cobj) != 0) {
5521 obj_extract_self(item);
5522 place_object(item, obj->ox, obj->oy);
5524 if (by_you && Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC)) {
5526 You_feel("guilty about damaging such a historic statue.");
5528 You_feel("
\82±
\82Ì
\82æ
\82¤
\82È
\97ð
\8ej
\93I
\82È
\92¤
\91\9c\82É
\8f\9d\82ð
\82Â
\82¯
\82é
\82Ì
\82Í
\8dß
\90[
\82¢
\82±
\82Æ
\82¾
\82Æ
\8ev
\82Á
\82½
\81D");
5537 * destroy_strings[dindx][0:singular,1:plural,2:killer_reason]
5538 * [0] freezing potion
5539 * [1] boiling potion other than oil
5540 * [2] boiling potion of oil
5541 * [3] burning scroll
5542 * [4] burning spellbook
5545 * (books, rings, and wands don't stack so don't need plural form;
5546 * crumbling ring doesn't do damage so doesn't need killer reason)
5548 const char *const destroy_strings[][3] = {
5549 /* also used in trap.c */
5551 { "freezes and shatters", "freeze and shatter", "shattered potion" },
5553 { "
\93\80\8c\8b\82µ
\82Ä
\8dÓ
\82¯
\82½", "
\93\80\8c\8b\82µ
\82Ä
\8dÓ
\82¯
\82½", "
\8dÓ
\82¯
\82½
\96ò
\95r
\82Å" },
5555 { "boils and explodes", "boil and explode", "boiling potion" },
5557 { "
\95¦
\93«
\82µ
\82Ä
\94\9a\94
\82µ
\82½", "
\95¦
\93«
\82µ
\82Ä
\94\9a\94
\82µ
\82½", "
\95¦
\93«
\82µ
\82½
\96ò
\82Å" },
5559 { "ignites and explodes", "ignite and explode", "exploding potion" },
5561 { "
\89Î
\82ª
\82Â
\82¢
\82Ä
\94\9a\94
\82µ
\82½", "
\89Î
\82ª
\82Â
\82¢
\82Ä
\94\9a\94
\82µ
\82½", "
\94\9a\94
\82µ
\82½
\96ò
\82Å" },
5563 { "catches fire and burns", "catch fire and burn", "burning scroll" },
5565 { "
\89Î
\82ª
\82Â
\82¢
\82Ä
\94R
\82¦
\82½", "
\89Î
\82ª
\82Â
\82¢
\82Ä
\94R
\82¦
\82½", "
\94R
\82¦
\82½
\8aª
\95¨
\82Å" },
5567 { "catches fire and burns", "", "burning book" },
5569 { "
\89Î
\82ª
\82Â
\82¢
\82Ä
\94R
\82¦
\82½", "
\89Î
\82ª
\82Â
\82¢
\82Ä
\94R
\82¦
\82½", "
\94R
\82¦
\82½
\96\82\96@
\8f\91\82Å" },
5571 { "turns to dust and vanishes", "", "" },
5573 { "
\90o
\82É
\82È
\82Á
\82Ä
\8fÁ
\82¦
\82½", "
\90o
\82É
\82È
\82Á
\82Ä
\8fÁ
\82¦
\82½", "" },
5575 { "breaks apart and explodes", "", "exploding wand" },
5577 { "
\82Î
\82ç
\82Î
\82ç
\82É
\89ó
\82ê
\82Ä
\94\9a\94
\82µ
\82½", "
\82Î
\82ç
\82Î
\82ç
\82É
\89ó
\82ê
\82Ä
\94\9a\94
\82µ
\82½", "
\8fñ
\82Ì
\94\9a\94
\82Å" },
5580 /* guts of destroy_item(), which ought to be called maybe_destroy_items();
5581 caller must decide whether obj is eligible */
5583 destroy_one_item(obj, osym, dmgtyp)
5588 int dmg, xresist, skip, dindx;
5590 boolean physical_damage;
5592 physical_damage = FALSE;
5594 /* lint suppression */
5600 if (osym == POTION_CLASS && obj->otyp != POT_OIL) {
5608 xresist = (Fire_resistance && obj->oclass != POTION_CLASS
5609 && obj->otyp != GLOB_OF_GREEN_SLIME);
5610 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
5612 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
5616 pline("%s glows a strange %s, but remains intact.",
5617 The(xname(obj)), hcolor("dark red"));
5619 pline("%s
\82Í
\8aï
\96
\82É%s
\8bP
\82¢
\82½
\82ª
\89½
\82à
\95Ï
\89»
\82µ
\82È
\82©
\82Á
\82½
\81D",
5620 xname(obj), jconj_adj(hcolor("
\88Ã
\8a\8c\90F
\82Ì")));
5626 dindx = (obj->otyp != POT_OIL) ? 1 : 2;
5638 if (obj->otyp == GLOB_OF_GREEN_SLIME) {
5639 dindx = 1; /* boil and explode */
5640 dmg = (obj->owt + 19) / 20;
5651 xresist = (Shock_resistance && obj->oclass != RING_CLASS);
5655 if (obj->otyp == RIN_SHOCK_RESISTANCE) {
5663 if (obj->otyp == WAN_LIGHTNING) {
5668 if (obj == current_wand) { skip++; break; }
5685 --quan; /* one will be used up elsewhere */
5686 for (i = cnt = 0L; i < quan; i++)
5694 ? ((quan == 1L) ? "Your" /* 1 of 1 */
5695 : "One of your") /* 1 of N */
5696 : ((cnt < quan) ? "Some of your" /* n of N */
5697 : (quan == 2L) ? "Both of your" /* 2 of 2 */
5698 : "All of your"); /* N of N */
5699 pline("%s %s %s!", mult, xname(obj),
5700 destroy_strings[dindx][(cnt > 1L)]);
5703 ? ((quan == 1L) ? "" /* 1 of 1 */
5704 : "
\82Ì
\82Ð
\82Æ
\82Â") /* 1 of N */
5705 : ((cnt < quan) ? "
\82Ì
\82¢
\82
\82Â
\82©" /* n of N */
5706 : "
\82Ì
\91S
\82Ä"); /* N of N */
5707 pline("
\82 \82È
\82½
\82Ì%s%s
\82Í%s
\81I", xname(obj), mult,
5708 destroy_strings[dindx][(cnt > 1L)]);
5710 if (osym == POTION_CLASS && dmgtyp != AD_COLD) {
5711 if (!breathless(youmonst.data) || haseyes(youmonst.data))
5714 if (obj->owornmask) {
5715 if (obj->owornmask & W_RING) /* ring being worn */
5720 if (obj == current_wand)
5721 current_wand = 0; /* destroyed */
5722 for (i = 0; i < cnt; i++)
5727 You("aren't hurt!");
5729 You("
\8f\9d\82Â
\82©
\82È
\82¢
\81I");
5731 const char *how = destroy_strings[dindx][2];
5732 boolean one = (cnt == 1L);
5734 if (dmgtyp == AD_FIRE && osym == FOOD_CLASS)
5736 how = "exploding glob of slime";
5738 how = "
\83X
\83\89\83C
\83\80\82Ì
\82Ë
\82Î
\82Ë
\82Î
\82Ì
\94\9a\94
\82Å";
5739 if (physical_damage)
5740 dmg = Maybe_Half_Phys(dmg);
5741 losehp(dmg, one ? how : (const char *) makeplural(how),
5742 one ? KILLED_BY_AN : KILLED_BY);
5743 exercise(A_STR, FALSE);
5749 /* target items of specified class for possible destruction */
5751 destroy_item(osym, dmgtyp)
5754 register struct obj *obj;
5755 int i, deferral_indx = 0;
5756 /* 1+52+1: try to handle a full inventory; it doesn't matter if
5757 inventory actually has more, even if everything should be deferred */
5758 unsigned short deferrals[1 + 52 + 1]; /* +1: gold, overflow */
5760 (void) memset((genericptr_t) deferrals, 0, sizeof deferrals);
5762 * Sometimes destroying an item can change inventory aside from
5763 * the item itself (cited case was a potion of unholy water; when
5764 * boiled, potionbreathe() caused hero to transform into were-beast
5765 * form and that resulted in dropping or destroying some worn armor).
5767 * Unlike other uses of the object bybass mechanism, destroy_item()
5768 * can be called multiple times for the same event. So we have to
5769 * explicitly clear it before each use and hope no other section of
5770 * code expects it to retain previous value.
5772 * Destruction of a ring of levitation or form change which pushes
5773 * off levitation boots could drop hero onto a fire trap that
5774 * could destroy other items and we'll get called recursively. Or
5775 * onto a trap which transports hero elsewhere, which won't disrupt
5776 * traversal but could yield message sequencing issues. So we
5777 * defer handling such things until after rest of inventory has
5778 * been processed. If some other combination of items and events
5779 * triggers a recursive call, rest of inventory after the triggering
5780 * item will be skipped by the outer call since the inner one will
5781 * have set the bypass bits of the whole list.
5783 * [Unfortunately, death while poly'd into flyer and subsequent
5784 * rehumanization could also drop hero onto a trap, and there's no
5785 * straightforward way to defer that. Things could be improved by
5786 * redoing this to use two passes, first to collect a list or array
5787 * of o_id and quantity of what is targetted for destruction,
5788 * second pass to handle the destruction.]
5790 bypass_objlist(invent, FALSE); /* clear bypass bit for invent */
5792 while ((obj = nxt_unbypassed_obj(invent)) != 0) {
5793 if (obj->oclass != osym)
5794 continue; /* test only objs of type osym */
5796 continue; /* don't destroy artifacts */
5797 if (obj->in_use && obj->quan == 1L)
5798 continue; /* not available */
5800 /* if loss of this item might dump us onto a trap, hold off
5801 until later because potential recursive destroy_item() will
5802 result in setting bypass bits on whole chain--we would skip
5803 the rest as already processed once control returns here */
5804 if (deferral_indx < SIZE(deferrals)
5805 && ((obj->owornmask != 0L
5806 && (objects[obj->otyp].oc_oprop == LEVITATION
5807 || objects[obj->otyp].oc_oprop == FLYING))
5808 /* destroyed wands and potions of polymorph don't trigger
5809 polymorph so don't need to be deferred */
5810 || (obj->otyp == POT_WATER && u.ulycn >= LOW_PM
5811 && (Upolyd ? obj->blessed : obj->cursed)))) {
5812 deferrals[deferral_indx++] = obj->o_id;
5815 /* obj is eligible; maybe destroy it */
5816 destroy_one_item(obj, osym, dmgtyp);
5818 /* if we saved some items for later (most likely just a worn ring
5819 of levitation) and they're still in inventory, handle them now */
5820 for (i = 0; i < deferral_indx; ++i) {
5821 /* note: obj->nobj is only referenced when obj is skipped;
5822 having obj be dropped or destroyed won't affect traversal */
5823 for (obj = invent; obj; obj = obj->nobj)
5824 if (obj->o_id == deferrals[i]) {
5825 destroy_one_item(obj, osym, dmgtyp);
5833 destroy_mitem(mtmp, osym, dmgtyp)
5843 if (mtmp == &youmonst) { /* this simplifies artifact_hit() */
5844 destroy_item(osym, dmgtyp);
5845 return 0; /* arbitrary; value doesn't matter to artifact_hit() */
5848 vis = canseemon(mtmp);
5850 /* see destroy_item(); object destruction could disrupt inventory list */
5851 bypass_objlist(mtmp->minvent, FALSE); /* clear bypass bit for minvent */
5853 while ((obj = nxt_unbypassed_obj(mtmp->minvent)) != 0) {
5854 if (obj->oclass != osym)
5855 continue; /* test only objs of type osym */
5862 if (osym == POTION_CLASS && obj->otyp != POT_OIL) {
5870 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
5872 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
5876 pline("%s glows a strange %s, but remains intact.",
5877 The(distant_name(obj, xname)), hcolor("dark red"));
5879 pline("%s
\82Í
\8aï
\96
\82É%s
\8bP
\82¢
\82½
\82ª
\89½
\82à
\95Ï
\89»
\82µ
\82È
\82©
\82Á
\82½
\81D",
5880 The(distant_name(obj, xname)), jconj_adj(hcolor("
\88Ã
\8a\8c\90F
\82Ì")));
5886 dindx = (obj->otyp != POT_OIL) ? 1 : 2;
5898 if (obj->otyp == GLOB_OF_GREEN_SLIME) {
5899 dindx = 1; /* boil and explode */
5900 tmp += (obj->owt + 19) / 20;
5914 if (obj->otyp == RIN_SHOCK_RESISTANCE) {
5921 if (obj->otyp == WAN_LIGHTNING) {
5938 for (i = cnt = 0L; i < quan; i++)
5947 (cnt == obj->quan) ? "" : (cnt > 1L) ? "Some of "
5949 (cnt == obj->quan) ? Yname2(obj) : yname(obj),
5950 destroy_strings[dindx][(cnt > 1L)]);
5952 pline("%s%s
\82Í%s
\81I",
5953 (cnt == obj->quan) ? Yname2(obj) : yname(obj),
5954 (cnt == obj->quan) ? "" : (cnt > 1L) ? "
\82Ì
\82¢
\82
\82Â
\82©"
5955 : "
\82Ì
\82Ð
\82Æ
\82Â",
5956 destroy_strings[dindx][(cnt > 1L)]);
5958 for (i = 0; i < cnt; i++)
5966 resist(mtmp, oclass, damage, tell)
5974 /* fake players always pass resistance test against Conflict
5975 (this doesn't guarantee that they're never affected by it) */
5976 if (oclass == RING_CLASS && !damage && !tell && is_mplayer(mtmp->data))
5986 break; /* instrument */
5989 break; /* artifact */
6004 dlev = (int) mtmp->m_lev;
6008 dlev = is_mplayer(mtmp->data) ? u.ulevel : 1;
6010 resisted = rn2(100 + alev - dlev) < mtmp->data->mr;
6013 shieldeff(mtmp->mx, mtmp->my);
6015 pline("%s resists!", Monnam(mtmp));
6017 pline("%s
\82Í
\96h
\82¢
\82¾
\81I", Monnam(mtmp));
6019 damage = (damage + 1) / 2;
6023 mtmp->mhp -= damage;
6024 if (DEADMONSTER(mtmp)) {
6026 monkilled(mtmp, "", AD_RBRE);
6034 #define MAXWISHTRY 5
6037 wishcmdassist(triesleft)
6040 static NEARDATA const char *
6044 "Enter the name of an object, such as \"potion of monster detection\",",
6045 "\"scroll labeled README\", \"elven mithril-coat\", or \"Grimtooth\"",
6046 "(without the quotes).",
6048 "For object types which come in stacks, you may specify a plural name",
6049 "such as \"potions of healing\", or specify a count, such as \"1000 gold",
6050 "pieces\", although that aspect of your wish might not be granted.",
6052 "You may also specify various prefix values which might be used to",
6053 "modify the item, such as \"uncursed\" or \"rustproof\" or \"+1\".",
6054 "Most modifiers shown when viewing your inventory can be specified.",
6056 "You may specify 'nothing' to explicitly decline this wish.",
6059 preserve_wishless[] = "Doing so will preserve 'wishless' conduct.",
6061 "If you specify an unrecognized object name %s%s time%s,",
6062 retry_too[] = "a randomly chosen item will be granted.",
6063 suppress_cmdassist[] =
6064 "(Suppress this assistance with !cmdassist in your config file.)",
6065 *cardinals[] = { "zero", "one", "two", "three", "four", "five" },
6066 too_many[] = "too many";
6071 win = create_nhwindow(NHW_TEXT);
6074 for (i = 0; i < SIZE(wishinfo) - 1; ++i)
6075 putstr(win, 0, wishinfo[i]);
6076 if (!u.uconduct.wishes)
6077 putstr(win, 0, preserve_wishless);
6079 Sprintf(buf, retry_info,
6080 (triesleft >= 0 && triesleft < SIZE(cardinals))
6081 ? cardinals[triesleft]
6083 (triesleft < MAXWISHTRY) ? " more" : "",
6085 putstr(win, 0, buf);
6086 putstr(win, 0, retry_too);
6088 if (iflags.cmdassist)
6089 putstr(win, 0, suppress_cmdassist);
6090 display_nhwindow(win, FALSE);
6091 destroy_nhwindow(win);
6097 char buf[BUFSZ] = DUMMY;
6098 char promptbuf[BUFSZ];
6099 struct obj *otmp, nothing;
6102 promptbuf[0] = '\0';
6103 nothing = zeroobj; /* lint suppression; only its address matters */
6106 You("may wish for an object.");
6108 You("
\96]
\82Ý
\82Ì
\82à
\82Ì
\82ð
\8eè
\82É
\93ü
\82ê
\82ç
\82ê
\82é
\81D");
6111 Strcpy(promptbuf, "For what do you wish");
6113 Strcpy(promptbuf, "(
\93ú
\96{
\8cê
\82Å)
\89½
\82ð
\82¨
\96]
\82Ý");
6114 if (iflags.cmdassist && tries > 0)
6116 Strcat(promptbuf, " (enter 'help' for assistance)");
6118 Strcat(promptbuf, " (
\8f\95\82¯
\82ª
\95K
\97v
\82È
\82ç 'help'
\82Æ
\93ü
\97Í)");
6120 Strcat(promptbuf, "?");
6122 Strcat(promptbuf, "
\81H");
6123 getlin(promptbuf, buf);
6124 (void) mungspaces(buf);
6125 if (buf[0] == '\033') {
6127 } else if (!strcmpi(buf, "help")) {
6128 wishcmdassist(MAXWISHTRY - tries);
6129 buf[0] = '\0'; /* for EDIT_GETLIN */
6133 * Note: if they wished for and got a non-object successfully,
6134 * otmp == &zeroobj. That includes gold, or an artifact that
6135 * has been denied. Wishing for "nothing" requires a separate
6136 * value to remain distinct.
6138 otmp = readobjnam(buf, ¬hing);
6141 pline("Nothing fitting that description exists in the game.");
6143 pline("
\82¤
\81[
\82ñ
\81D
\82»
\82ñ
\82È
\82à
\82Ì
\82Í
\91¶
\8dÝ
\82µ
\82È
\82¢
\82æ
\82¤
\82¾
\81D");
6144 if (++tries < MAXWISHTRY)
6146 pline1(thats_enough_tries);
6147 otmp = readobjnam((char *) 0, (struct obj *) 0);
6149 return; /* for safety; should never happen */
6150 } else if (otmp == ¬hing) {
6151 /* explicitly wished for "nothing", presumably attempting
6152 to retain wishless conduct */
6157 u.uconduct.wishes++;
6159 if (otmp != &zeroobj) {
6162 *verb = ((Is_airlevel(&u.uz) || u.uinwater) ? "slip" : "drop"),
6164 *verb = ((Is_airlevel(&u.uz) || u.uinwater) ? "
\8a\8a\82è
\97\8e\82¿
\82½" : "
\97\8e\82¿
\82½"),
6166 *oops_msg = (u.uswallow
6167 ? "Oops! %s out of your reach!"
6168 : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
6169 || levl[u.ux][u.uy].typ < IRONBARS
6170 || levl[u.ux][u.uy].typ >= ICE)
6171 ? "Oops! %s away from you!"
6172 : "Oops! %s to the floor!");
6174 /* The(aobjnam()) is safe since otmp is unidentified -dlc */
6175 (void) hold_another_object(otmp, oops_msg,
6176 The(aobjnam(otmp, verb)),
6179 *oops_msg = (u.uswallow
6180 ? "
\82¨
\82Á
\82Æ
\81C%%s
\82ª
\93Í
\82©
\82È
\82¢
\82Æ
\82±
\82ë
\82É%s
\81I"
6181 : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
6182 || levl[u.ux][u.uy].typ < IRONBARS
6183 || levl[u.ux][u.uy].typ >= ICE)
6184 ? "
\82¨
\82Á
\82Æ
\81C%%s
\82ª
\8eè
\82©
\82ç%s
\81I"
6185 : "
\82¨
\82Á
\82Æ
\81C%%s
\82ª
\8f°
\82É%s
\81I");
6186 char oopsbuf[BUFSZ];
6187 Sprintf(oopsbuf, oops_msg, verb);
6189 (void) hold_another_object(otmp, oopsbuf,
6193 u.ublesscnt += rn1(100, 50); /* the gods take notice */