1 /* NetHack 3.6 zap.c $NHDT-Date: 1551395521 2019/02/28 23:12:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.307 $ */
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-2019 */
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);
179 /* Routines for IMMEDIATE wands and spells. */
180 /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */
186 boolean wake = TRUE; /* Most 'zaps' should wake monster */
187 boolean reveal_invis = FALSE, learn_it = FALSE;
188 boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart;
189 boolean skilled_spell, helpful_gesture = FALSE;
190 int dmg, otyp = otmp->otyp;
192 const char *zap_type_text = "spell";
194 const char *zap_type_text = "
\96\82\96@";
196 boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC
197 && M_AP_TYPE(mtmp) != M_AP_NOTHING);
199 if (u.uswallow && mtmp == u.ustuck)
200 reveal_invis = FALSE;
202 notonhead = (mtmp->mx != bhitpos.x || mtmp->my != bhitpos.y);
203 skilled_spell = (otmp && otmp->oclass == SPBOOK_CLASS && otmp->blessed);
208 zap_type_text = "wand";
210 zap_type_text = "
\8fñ";
216 if (resists_magm(mtmp)) { /* match effect on player */
217 shieldeff(mtmp->mx, mtmp->my);
221 pline("
\83{
\83C
\83\93\81I");
222 break; /* skip makeknown */
223 } else if (u.uswallow || rnd(20) < 10 + find_mac(mtmp)) {
227 if (otyp == SPE_FORCE_BOLT)
228 dmg = spell_damage_bonus(dmg);
229 hit(zap_type_text, mtmp, exclam(dmg));
230 (void) resist(mtmp, otmp->oclass, dmg, TELL);
232 miss(zap_type_text, mtmp);
235 case WAN_SLOW_MONSTER:
236 case SPE_SLOW_MONSTER:
237 if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
240 mon_adjust_speed(mtmp, -1, otmp);
241 m_dowear(mtmp, FALSE); /* might want speed boots */
242 if (u.uswallow && (mtmp == u.ustuck) && is_whirly(mtmp->data)) {
244 You("disrupt %s!", mon_nam(mtmp));
246 You("%s
\82ð
\83o
\83\89\83o
\83\89\82É
\82µ
\82½
\81I", mon_nam(mtmp));
248 pline("A huge hole opens up...");
250 pline("
\92E
\8fo
\82Å
\82«
\82»
\82¤
\82È
\8c\8a\82ª
\8aJ
\82¢
\82½
\81D
\81D
\81D");
251 expels(mtmp, mtmp->data, TRUE);
255 case WAN_SPEED_MONSTER:
256 if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
259 mon_adjust_speed(mtmp, 1, otmp);
260 m_dowear(mtmp, FALSE); /* might want speed boots */
263 helpful_gesture = TRUE;
265 case WAN_UNDEAD_TURNING:
266 case SPE_TURN_UNDEAD:
268 if (unturn_dead(mtmp))
270 if (is_undead(mtmp->data) || is_vampshifter(mtmp)) {
276 if (otyp == SPE_TURN_UNDEAD)
277 dmg = spell_damage_bonus(dmg);
278 context.bypasses = TRUE; /* for make_corpse() */
279 if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) {
280 if (!DEADMONSTER(mtmp))
281 monflee(mtmp, 0, FALSE, TRUE);
288 if (mtmp->data == &mons[PM_LONG_WORM] && has_mcorpsenm(mtmp)) {
289 /* if a long worm has mcorpsenm set, it was polymophed by
290 the current zap and shouldn't be affected if hit again */
292 } else if (resists_magm(mtmp)) {
293 /* magic resistance protects from polymorph traps, so make
294 it guard against involuntary polymorph attacks too... */
295 shieldeff(mtmp->mx, mtmp->my);
296 } else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
297 boolean polyspot = (otyp != POT_POLYMORPH),
298 give_msg = (!Hallucination
300 || (u.uswallow && mtmp == u.ustuck)));
302 /* dropped inventory (due to death by system shock,
303 or loss of wielded weapon and/or worn armor due to
304 limitations of new shape) won't be hit by this zap */
306 for (obj = mtmp->minvent; obj; obj = obj->nobj)
309 /* natural shapechangers aren't affected by system shock
310 (unless protection from shapechangers is interfering
311 with their metabolism...) */
312 if (mtmp->cham == NON_PM && !rn2(25)) {
313 if (canseemon(mtmp)) {
315 pline("%s shudders!", Monnam(mtmp));
317 pline("%s
\82Í
\90g
\90k
\82¢
\82µ
\82½
\81I", Monnam(mtmp));
320 /* context.bypasses = TRUE; ## for make_corpse() */
321 /* no corpse after system shock */
322 xkilled(mtmp, XKILL_GIVEMSG | XKILL_NOCORPSE);
323 } else if (newcham(mtmp, (struct permonst *) 0,
324 polyspot, give_msg) != 0
325 /* if shapechange failed because there aren't
326 enough eligible candidates (most likely for
327 vampshifter), try reverting to original form */
328 || (mtmp->cham >= LOW_PM
329 && newcham(mtmp, &mons[mtmp->cham],
330 polyspot, give_msg) != 0)) {
331 if (give_msg && (canspotmon(mtmp)
332 || (u.uswallow && mtmp == u.ustuck)))
336 /* do this even if polymorphed failed (otherwise using
337 flags.mon_polycontrol prompting to force mtmp to remain
338 'long worm' would prompt again if zap hit another segment) */
339 if (!DEADMONSTER(mtmp) && mtmp->data == &mons[PM_LONG_WORM]) {
340 if (!has_mcorpsenm(mtmp))
342 /* flag to indicate that mtmp became a long worm
343 on current zap, so further hits (on mtmp's new
344 tail) don't do further transforms */
345 MCORPSENM(mtmp) = PM_LONG_WORM;
346 /* flag to indicate that cleanup is needed; object
347 bypass cleanup also clears mon->mextra->mcorpsenm
348 for all long worms on the level */
349 context.bypasses = TRUE;
353 case WAN_CANCELLATION:
354 case SPE_CANCELLATION:
357 (void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE);
359 case WAN_TELEPORTATION:
360 case SPE_TELEPORT_AWAY:
363 reveal_invis = !u_teleport_mon(mtmp, TRUE);
365 case WAN_MAKE_INVISIBLE: {
366 int oldinvis = mtmp->minvis;
371 /* format monster's name before altering its visibility */
372 Strcpy(nambuf, Monnam(mtmp));
373 mon_set_minvis(mtmp);
374 if (!oldinvis && knowninvisible(mtmp)) {
376 pline("%s turns transparent!", nambuf);
378 pline("%s
\82Í
\93§
\96¾
\82É
\82È
\82Á
\82½
\81I", nambuf);
385 case SPE_WIZARD_LOCK:
386 wake = closeholdingtrap(mtmp, &learn_it);
396 wake = FALSE; /* don't want immediate counterattack */
397 if (u.uswallow && mtmp == u.ustuck) {
398 if (is_animal(mtmp->data)) {
401 You_feel("a sudden rush of air!");
403 You("
\93Ë
\91R
\8c\83\82µ
\82¢
\8bó
\8bC
\82Ì
\97¬
\82ê
\82ð
\8a´
\82¶
\82½
\81I");
406 pline("%s opens its mouth!", Monnam(mtmp));
408 pline("%s
\82Í
\8cû
\82ð
\8aJ
\82¢
\82½
\81I", Monnam(mtmp));
410 expels(mtmp, mtmp->data, TRUE);
411 /* zap which hits steed will only release saddle if it
412 doesn't hit a holding or falling trap; playability
413 here overrides the more logical target ordering */
414 } else if (openholdingtrap(mtmp, &learn_it)) {
416 } else if (openfallingtrap(mtmp, TRUE, &learn_it)) {
417 /* mtmp might now be on the migrating monsters list */
419 } else if ((obj = which_armor(mtmp, W_SADDLE)) != 0) {
423 Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)),
424 distant_name(obj, xname));
426 Sprintf(buf, "%s
\82Ì%s", Monnam(mtmp),
427 distant_name(obj, xname));
429 if (cansee(mtmp->mx, mtmp->my)) {
430 if (!canspotmon(mtmp))
431 Strcpy(buf, An(distant_name(obj, xname)));
433 pline("%s falls to the %s.", buf,
434 surface(mtmp->mx, mtmp->my));
436 pline("%s
\82Í%s
\82É
\97\8e\82¿
\82½
\81D", buf,
437 surface(mtmp->mx, mtmp->my));
439 } else if (canspotmon(mtmp)) {
441 pline("%s falls off.", buf);
443 pline("%s
\82ª
\97\8e\82¿
\82½
\81D", buf);
445 obj_extract_self(obj);
446 mdrop_obj(mtmp, obj, FALSE);
450 case SPE_EXTRA_HEALING:
452 if (mtmp->data != &mons[PM_PESTILENCE]) {
453 wake = FALSE; /* wakeup() makes the target angry */
454 mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4);
455 if (mtmp->mhp > mtmp->mhpmax)
456 mtmp->mhp = mtmp->mhpmax;
457 /* plain healing must be blessed to cure blindness; extra
458 healing only needs to not be cursed, so spell always cures
459 [potions quaffed by monsters behave slightly differently;
460 we use the rules for the hero here...] */
461 if (skilled_spell || otyp == SPE_EXTRA_HEALING)
462 mcureblindness(mtmp, canseemon(mtmp));
463 if (canseemon(mtmp)) {
464 if (disguised_mimic) {
465 if (is_obj_mappear(mtmp,STRANGE_OBJECT)) {
466 /* it can do better now */
468 newsym(mtmp->mx, mtmp->my);
470 mimic_hit_msg(mtmp, otyp);
473 pline("%s looks%s better.", Monnam(mtmp),
474 otyp == SPE_EXTRA_HEALING ? " much" : "");
476 pline("%s
\82Í%s
\8c³
\8bC
\82É
\82È
\82Á
\82½
\82æ
\82¤
\82¾
\81D", Monnam(mtmp),
477 otyp == SPE_EXTRA_HEALING ? "
\82Æ
\82Ä
\82à" : "" );
480 if (mtmp->mtame || mtmp->mpeaceful) {
481 adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type));
483 } else { /* Pestilence */
484 /* Pestilence will always resist; damage is half of 3d{4,8} */
485 (void) resist(mtmp, otmp->oclass,
486 d(3, otyp == SPE_EXTRA_HEALING ? 8 : 4), TELL);
489 case WAN_LIGHT: /* (broken wand) */
490 if (flash_hits_mon(mtmp, otmp)) {
495 case WAN_SLEEP: /* (broken wand) */
496 /* [wakeup() doesn't rouse victims of temporary sleep,
497 so it's okay to leave `wake' set to TRUE here] */
499 if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS))
504 case SPE_STONE_TO_FLESH:
505 if (monsndx(mtmp->data) == PM_STONE_GOLEM) {
506 char *name = Monnam(mtmp);
508 /* turn into flesh golem */
509 if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE, FALSE)) {
512 pline("%s turns to flesh!", name);
514 pline("%s
\82Ì
\90Î
\89»
\82ª
\89ð
\82¯
\82½
\81I", name);
518 pline("%s looks rather fleshy for a moment.", name);
520 pline("%s
\82Í
\88ê
\8fu
\90Î
\89»
\82ª
\89ð
\82¯
\82½
\81D", name);
528 dmg = monhp_per_lvl(mtmp);
531 if (otyp == SPE_DRAIN_LIFE)
532 dmg = spell_damage_bonus(dmg);
533 if (resists_drli(mtmp)) {
534 shieldeff(mtmp->mx, mtmp->my);
535 } else if (!resist(mtmp, otmp->oclass, dmg, NOTELL)
536 && !DEADMONSTER(mtmp)) {
539 /* die if already level 0, regardless of hit points */
540 if (DEADMONSTER(mtmp) || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) {
546 pline("%s suddenly seems weaker!", Monnam(mtmp));
548 pline("%s
\82Í
\82Æ
\82Â
\82º
\82ñ
\8eã
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I", Monnam(mtmp));
556 impossible("What an interesting effect (%d)", otyp);
560 if (!DEADMONSTER(mtmp)) {
561 wakeup(mtmp, helpful_gesture ? FALSE : TRUE);
563 if (mtmp->isshk && !*u.ushops)
565 } else if (M_AP_TYPE(mtmp))
566 seemimic(mtmp); /* might unblock if mimicing a boulder/door */
568 /* note: bhitpos won't be set if swallowed, but that's okay since
569 * reveal_invis will be false. We can't use mtmp->mx, my since it
570 * might be an invisible worm hit on the tail.
573 if (!DEADMONSTER(mtmp) && cansee(bhitpos.x, bhitpos.y)
574 && !canspotmon(mtmp))
575 map_invisible(bhitpos.x, bhitpos.y);
577 /* if effect was observable then discover the wand type provided
578 that the wand itself has been seen */
592 return; /* don't show minvent for long worm tail */
595 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
596 otmp->dknown = 1; /* treat as "seen" */
597 if (Is_container(otmp) || otmp->otyp == STATUE) {
599 if (!SchroedingersBox(otmp))
603 (void) display_minventory(mtmp, MINV_ALL | MINV_NOLET | PICK_NONE,
607 pline("%s is not carrying anything%s.", noit_Monnam(mtmp),
608 (u.uswallow && mtmp == u.ustuck) ? " besides you" : "");
610 pline("%s
\82Í%s
\89½
\82à
\8e\9d\82Á
\82Ä
\82¢
\82È
\82¢
\81D", noit_Monnam(mtmp),
611 (u.uswallow && mtmp == u.ustuck) ? "
\82 \82È
\82½
\88È
\8aO
\82É" : "");
617 * Return the object's physical location. This only makes sense for
618 * objects that are currently on the level (i.e. migrating objects
619 * are nowhere). By default, only things that can be seen (in hero's
620 * inventory, monster's inventory, or on the ground) are reported.
621 * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get
622 * the location of buried and contained objects. Note that if an
623 * object is carried by a monster, its reported position may change
624 * from turn to turn. This function returns FALSE if the position
625 * is not available or subject to the constraints above.
628 get_obj_location(obj, xp, yp, locflags)
633 switch (obj->where) {
643 if (obj->ocarry->mx) {
644 *xp = obj->ocarry->mx;
645 *yp = obj->ocarry->my;
648 break; /* !mx => migrating monster */
650 if (locflags & BURIED_TOO) {
657 if (locflags & CONTAINED_TOO)
658 return get_obj_location(obj->ocontainer, xp, yp, locflags);
666 get_mon_location(mon, xp, yp, locflags)
669 int locflags; /* non-zero means get location even if monster is buried */
671 if (mon == &youmonst) {
675 } else if (mon->mx > 0 && (!mon->mburied || locflags)) {
679 } else { /* migrating or buried */
685 /* used by revive() and animate_statue() */
687 montraits(obj, cc, adjacentok)
690 boolean adjacentok; /* False: at obj's spot only, True: nearby is allowed */
692 struct monst *mtmp = (struct monst *) 0;
693 struct monst *mtmp2 = (struct monst *) 0;
696 mtmp2 = get_mtraits(obj, TRUE);
698 /* save_mtraits() validated mtmp2->mnum */
699 mtmp2->data = &mons[mtmp2->mnum];
700 if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data))
701 return (struct monst *) 0;
702 mtmp = makemon(mtmp2->data, cc->x, cc->y,
703 (NO_MINVENT | MM_NOWAIT | MM_NOCOUNTBIRTH
704 | (adjacentok ? MM_ADJACENTOK : 0)));
708 /* heal the monster */
709 if (mtmp->mhpmax > mtmp2->mhpmax && is_rider(mtmp2->data))
710 mtmp2->mhpmax = mtmp->mhpmax;
711 mtmp2->mhp = mtmp2->mhpmax;
712 /* Get these ones from mtmp */
713 mtmp2->minvent = mtmp->minvent; /*redundant*/
714 /* monster ID is available if the monster died in the current
715 game, but will be zero if the corpse was in a bones level
716 (we cleared it when loading bones) */
718 mtmp2->m_id = mtmp->m_id;
719 /* might be bringing quest leader back to life */
720 if (quest_status.leader_is_dead
721 /* leader_is_dead implies leader_m_id is valid */
722 && mtmp2->m_id == quest_status.leader_m_id)
723 quest_status.leader_is_dead = FALSE;
725 mtmp2->mx = mtmp->mx;
726 mtmp2->my = mtmp->my;
727 mtmp2->mux = mtmp->mux;
728 mtmp2->muy = mtmp->muy;
729 mtmp2->mw = mtmp->mw;
730 mtmp2->wormno = mtmp->wormno;
731 mtmp2->misc_worn_check = mtmp->misc_worn_check;
732 mtmp2->weapon_check = mtmp->weapon_check;
733 mtmp2->mtrapseen = mtmp->mtrapseen;
734 mtmp2->mflee = mtmp->mflee;
735 mtmp2->mburied = mtmp->mburied;
736 mtmp2->mundetected = mtmp->mundetected;
737 mtmp2->mfleetim = mtmp->mfleetim;
738 mtmp2->mlstmv = mtmp->mlstmv;
739 mtmp2->m_ap_type = mtmp->m_ap_type;
740 /* set these ones explicitly */
746 mtmp2->msleeping = 0;
749 /* most cancelled monsters return to normal,
750 but some need to stay cancelled */
751 if (!dmgtype(mtmp2->data, AD_SEDU)
752 && (!SYSOPT_SEDUCE || !dmgtype(mtmp2->data, AD_SSEX)))
754 mtmp2->mcansee = 1; /* set like in makemon */
758 /* when traits are for a shopeekper, dummy monster 'mtmp' won't
759 have necessary eshk data for replmon() -> replshk() */
762 *ESHK(mtmp) = *ESHK(mtmp2);
763 if (ESHK(mtmp2)->bill_p != 0
764 && ESHK(mtmp2)->bill_p != (struct bill_x *) -1000)
765 ESHK(mtmp)->bill_p = &(ESHK(mtmp)->bill[0]);
768 replmon(mtmp, mtmp2);
769 newsym(mtmp2->mx, mtmp2->my); /* Might now be invisible */
771 /* in case Protection_from_shape_changers is different
772 now than it was when the traits were stored */
779 * get_container_location() returns the following information
780 * about the outermost container:
781 * loc argument gets set to:
782 * OBJ_INVENT if in hero's inventory; return 0.
783 * OBJ_FLOOR if on the floor; return 0.
784 * OBJ_BURIED if buried; return 0.
785 * OBJ_MINVENT if in monster's inventory; return monster.
786 * container_nesting is updated with the nesting depth of the containers
790 get_container_location(obj, loc, container_nesting)
793 int *container_nesting;
798 if (container_nesting)
799 *container_nesting = 0;
800 while (obj && obj->where == OBJ_CONTAINED) {
801 if (container_nesting)
802 *container_nesting += 1;
803 obj = obj->ocontainer;
806 *loc = obj->where; /* outermost container's location */
807 if (obj->where == OBJ_MINVENT)
810 return (struct monst *) 0;
814 * Attempt to revive the given corpse, return the revived monster if
815 * successful. Note: this does NOT use up the corpse if it fails.
816 * If corpse->quan is more than 1, only one corpse will be affected
817 * and only one monster will be resurrected.
820 revive(corpse, by_hero)
824 struct monst *mtmp = 0;
825 struct permonst *mptr;
826 struct obj *container;
830 int montype, container_nesting = 0;
832 if (corpse->otyp != CORPSE) {
833 impossible("Attempting to revive %s?", xname(corpse));
834 return (struct monst *) 0;
838 if (corpse->where != OBJ_CONTAINED) {
839 /* only for invent, minvent, or floor */
841 (void) get_obj_location(corpse, &x, &y, 0);
843 /* deal with corpses in [possibly nested] containers */
844 struct monst *carrier;
845 int holder = OBJ_FREE;
847 container = corpse->ocontainer;
849 get_container_location(container, &holder, &container_nesting);
852 x = carrier->mx, y = carrier->my;
858 (void) get_obj_location(corpse, &x, &y, CONTAINED_TOO);
861 break; /* x,y are 0 */
865 /* Rules for revival from containers:
866 * - the container cannot be locked
867 * - the container cannot be heavily nested (>2 is arbitrary)
868 * - the container cannot be a statue or bag of holding
869 * (except in very rare cases for the latter)
871 || (container && (container->olocked || container_nesting > 2
872 || container->otyp == STATUE
873 || (container->otyp == BAG_OF_HOLDING && rn2(40)))))
874 return (struct monst *) 0;
876 /* record the object's location now that we're sure where it is */
877 corpse->ox = x, corpse->oy = y;
879 /* prepare for the monster */
880 montype = corpse->corpsenm;
881 mptr = &mons[montype];
882 /* [should probably handle recorporealization first; if corpse and
883 ghost are at same location, revived creature shouldn't be bumped
884 to an adjacent spot by ghost which joins with it] */
886 if (enexto(&xy, x, y, mptr))
890 if ((mons[montype].mlet == S_EEL && !IS_POOL(levl[x][y].typ))
891 || (mons[montype].mlet == S_TROLL
892 && uwep && uwep->oartifact == ART_TROLLSBANE)) {
893 if (by_hero && cansee(x, y))
895 pline("%s twitches feebly.",
897 pline("%s
\82Í
\82í
\82¸
\82©
\82Éáz
\9d¹
\82µ
\82½
\81D",
898 upstart(corpse_xname(corpse, (const char *) 0, CXN_PFX_THE)));
899 return (struct monst *) 0;
902 if (cant_revive(&montype, TRUE, corpse)) {
903 /* make a zombie or doppelganger instead */
904 /* note: montype has changed; mptr keeps old value for newcham() */
905 mtmp = makemon(&mons[montype], x, y, NO_MINVENT | MM_NOWAIT);
907 /* skip ghost handling */
908 if (has_omid(corpse))
910 if (has_omonst(corpse))
912 if (mtmp->cham == PM_DOPPELGANGER) {
913 /* change shape to match the corpse */
914 (void) newcham(mtmp, mptr, FALSE, FALSE);
915 } else if (mtmp->data->mlet == S_ZOMBIE) {
916 mtmp->mhp = mtmp->mhpmax = 100;
917 mon_adjust_speed(mtmp, 2, (struct obj *) 0); /* MFAST */
920 } else if (has_omonst(corpse)) {
921 /* use saved traits */
923 mtmp = montraits(corpse, &xy, FALSE);
924 if (mtmp && mtmp->mtame && !mtmp->isminion)
925 wary_dog(mtmp, TRUE);
927 /* make a new monster */
928 mtmp = makemon(mptr, x, y, NO_MINVENT | MM_NOWAIT | MM_NOCOUNTBIRTH);
931 return (struct monst *) 0;
933 /* hiders shouldn't already be re-hidden when they revive */
934 if (mtmp->mundetected) {
935 mtmp->mundetected = 0;
936 newsym(mtmp->mx, mtmp->my);
941 one_of = (corpse->quan > 1L);
943 corpse = splitobj(corpse, 1L);
945 /* if this is caused by the hero there might be a shop charge */
947 struct monst *shkp = 0;
949 x = corpse->ox, y = corpse->oy;
950 if (costly_spot(x, y)
951 && (carried(corpse) ? corpse->unpaid : !corpse->no_charge))
952 shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
957 #if 1 /*JP*//*
\8e\80\91Ì
\96¼
\82Í
\90æ
\82É; Strcpy
\82É
\82È
\82é */
958 Strcpy(buf, corpse_xname(corpse, (const char *) 0, CXN_NO_PFX));
961 Strcpy(buf, one_of ? "one of " : "");
962 #else /*
\8cê
\8f\87\82Í
\95Ï
\82í
\82Á
\82Ä
\82¢
\82é */
964 Strcat(buf, "
\82Ì
\88ê
\82Â");
967 #if 0 /*JP*//*
\82±
\82±
\82Å
\81u
\82 \82È
\82½
\82Ì
\81v
\82Í
\95s
\8e©
\91R */
968 /* shk_your: "the " or "your " or "<mon>'s " or "<Shk>'s ".
969 If the result is "Shk's " then it will be ambiguous:
970 is Shk the mon carrying it, or does Shk's shop own it?
971 Let's not worry about that... */
972 (void) shk_your(eos(buf), corpse);
975 corpse->quan++; /* force plural */
976 #if 0 /*JP*//*
\8aù
\82É
\90Ý
\92è
\8dÏ
\82Ý */
977 Strcat(buf, corpse_xname(corpse, (const char *) 0, CXN_NO_PFX));
979 if (one_of) /* could be simplified to ''corpse->quan = 1L;'' */
982 pline("%s glows iridescently.", upstart(buf));
984 pline("%s
\82Í
\93ø
\90F
\82É
\8bP
\82¢
\82½
\81D", upstart(buf));
986 /* need some prior description of the corpse since
987 stolen_value() will refer to the object as "it" */
989 pline("A corpse is resuscitated.");
991 pline("
\8e\80\91Ì
\82ª
\91h
\90¶
\82µ
\82½
\81D");
993 /* don't charge for shopkeeper's own corpse if we just revived him */
994 if (shkp && mtmp != shkp)
995 (void) stolen_value(corpse, x, y, (boolean) shkp->mpeaceful,
998 /* [we don't give any comparable message about the corpse for
999 the !by_hero case because caller might have already done so] */
1002 /* handle recorporealization of an active ghost */
1003 if (has_omid(corpse)) {
1005 struct monst *ghost;
1008 (void) memcpy((genericptr_t) &m_id, (genericptr_t) OMID(corpse),
1010 ghost = find_mid(m_id, FM_FMON);
1011 if (ghost && ghost->data == &mons[PM_GHOST]) {
1012 if (canseemon(ghost))
1014 pline("%s is suddenly drawn into its former body!",
1016 pline("%s
\82Í
\93Ë
\91R
\82à
\82Æ
\82Ì
\91Ì
\82É
\88ø
\82«
\8d\9e\82Ü
\82ê
\82½
\81I",
1019 /* transfer the ghost's inventory along with it */
1020 while ((otmp = ghost->minvent) != 0) {
1021 obj_extract_self(otmp);
1022 add_to_minv(mtmp, otmp);
1024 /* tame the revived monster if its ghost was tame */
1025 if (ghost->mtame && !mtmp->mtame) {
1026 if (tamedog(mtmp, (struct obj *) 0)) {
1027 /* ghost's edog data is ignored */
1028 mtmp->mtame = ghost->mtame;
1031 /* was ghost, now alive, it's all very confusing */
1033 /* separate ghost monster no longer exists */
1039 /* monster retains its name */
1040 if (has_oname(corpse) && !unique_corpstat(mtmp->data))
1041 mtmp = christen_monst(mtmp, ONAME(corpse));
1042 /* partially eaten corpse yields wounded monster */
1044 mtmp->mhp = eaten_stat(mtmp->mhp, corpse);
1045 /* track that this monster was revived at least once */
1048 /* finally, get rid of the corpse--it's gone now */
1049 switch (corpse->where) {
1054 /* in case MON_AT+enexto for invisible mon */
1055 x = corpse->ox, y = corpse->oy;
1056 /* not useupf(), which charges */
1057 if (corpse->quan > 1L)
1058 corpse = splitobj(corpse, 1L);
1063 m_useup(corpse->ocarry, corpse);
1066 obj_extract_self(corpse);
1067 obfree(corpse, (struct obj *) 0);
1081 * Note: generic eggs with corpsenm set to NON_PM will never hatch.
1083 if (obj->otyp != EGG)
1085 if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE))
1086 attach_egg_hatch_timeout(obj, 0L);
1089 /* try to revive all corpses and eggs carried by `mon' */
1094 struct obj *otmp, *otmp2;
1095 struct monst *mtmp2;
1096 char owner[BUFSZ], corpse[BUFSZ];
1100 youseeit = (mon == &youmonst) ? TRUE : canseemon(mon);
1101 otmp2 = (mon == &youmonst) ? invent : mon->minvent;
1102 owner[0] = corpse[0] = '\0'; /* lint suppression */
1104 while ((otmp = otmp2) != 0) {
1106 if (otmp->otyp == EGG)
1108 if (otmp->otyp != CORPSE)
1110 /* save the name; the object is liable to go away */
1113 corpse_xname(otmp, (const char *) 0, CXN_SINGULAR));
1114 Shk_Your(owner, otmp); /* includes a trailing space */
1117 /* for a stack, only one is revived */
1118 if ((mtmp2 = revive(otmp, !context.mon_moving)) != 0) {
1122 pline("%s%s suddenly comes alive!", owner, corpse);
1124 pline("%s%s
\82Í
\93Ë
\91R
\90¶
\96½
\82ð
\91Ñ
\82Ñ
\82½
\81I", owner, corpse);
1125 else if (canseemon(mtmp2))
1127 pline("%s suddenly appears!", Amonnam(mtmp2));
1129 pline("%s
\82ª
\93Ë
\91R
\8c»
\82í
\82ê
\82½
\81I", Amonnam(mtmp2));
1135 /* cancel obj, possibly carried by you or a monster */
1138 register struct obj *obj;
1140 boolean u_ring = (obj == uleft || obj == uright);
1141 int otyp = obj->otyp;
1144 case RIN_GAIN_STRENGTH:
1145 if ((obj->owornmask & W_RING) && u_ring) {
1146 ABON(A_STR) -= obj->spe;
1150 case RIN_GAIN_CONSTITUTION:
1151 if ((obj->owornmask & W_RING) && u_ring) {
1152 ABON(A_CON) -= obj->spe;
1157 if ((obj->owornmask & W_RING) && u_ring) {
1158 ABON(A_CHA) -= obj->spe;
1162 case RIN_INCREASE_ACCURACY:
1163 if ((obj->owornmask & W_RING) && u_ring)
1164 u.uhitinc -= obj->spe;
1166 case RIN_INCREASE_DAMAGE:
1167 if ((obj->owornmask & W_RING) && u_ring)
1168 u.udaminc -= obj->spe;
1170 case GAUNTLETS_OF_DEXTERITY:
1171 if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
1172 ABON(A_DEX) -= obj->spe;
1176 case HELM_OF_BRILLIANCE:
1177 if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
1178 ABON(A_INT) -= obj->spe;
1179 ABON(A_WIS) -= obj->spe;
1183 /* case RIN_PROTECTION: not needed */
1185 if (objects[otyp].oc_magic
1186 || (obj->spe && (obj->oclass == ARMOR_CLASS
1187 || obj->oclass == WEAPON_CLASS || is_weptool(obj)))
1189 || otyp == POT_SICKNESS
1190 || (otyp == POT_WATER && (obj->blessed || obj->cursed))) {
1191 if (obj->spe != ((obj->oclass == WAND_CLASS) ? -1 : 0)
1192 && otyp != WAN_CANCELLATION /* can't cancel cancellation */
1193 && otyp != MAGIC_LAMP /* cancelling doesn't remove djinni */
1194 && otyp != CANDELABRUM_OF_INVOCATION) {
1195 costly_alteration(obj, COST_CANCEL);
1196 obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0;
1198 switch (obj->oclass) {
1200 costly_alteration(obj, COST_CANCEL);
1201 obj->otyp = SCR_BLANK_PAPER;
1205 if (otyp != SPE_CANCELLATION && otyp != SPE_NOVEL
1206 && otyp != SPE_BOOK_OF_THE_DEAD) {
1207 costly_alteration(obj, COST_CANCEL);
1208 obj->otyp = SPE_BLANK_PAPER;
1212 costly_alteration(obj,
1215 : obj->cursed ? COST_UNCURS : COST_UNBLSS);
1216 if (otyp == POT_SICKNESS || otyp == POT_SEE_INVISIBLE) {
1217 /* sickness is "biologically contaminated" fruit juice;
1218 cancel it and it just becomes fruit juice...
1219 whereas see invisible tastes like "enchanted" fruit
1220 juice, it similarly cancels */
1221 obj->otyp = POT_FRUIT_JUICE;
1223 obj->otyp = POT_WATER;
1224 obj->odiluted = 0; /* same as any other water */
1234 /* Remove a positive enchantment or charge from obj,
1235 * possibly carried by you or a monster
1238 drain_item(obj, by_you)
1244 /* Is this a charged/enchanted object? */
1246 || (!objects[obj->otyp].oc_charged && obj->oclass != WEAPON_CLASS
1247 && obj->oclass != ARMOR_CLASS && !is_weptool(obj))
1250 if (defends(AD_DRLI, obj) || defends_when_carried(AD_DRLI, obj)
1251 || obj_resists(obj, 10, 90))
1254 /* Charge for the cost of the object */
1256 costly_alteration(obj, COST_DRAIN);
1258 /* Drain the object and any implied effects */
1260 u_ring = (obj == uleft) || (obj == uright);
1261 switch (obj->otyp) {
1262 case RIN_GAIN_STRENGTH:
1263 if ((obj->owornmask & W_RING) && u_ring) {
1268 case RIN_GAIN_CONSTITUTION:
1269 if ((obj->owornmask & W_RING) && u_ring) {
1275 if ((obj->owornmask & W_RING) && u_ring) {
1280 case RIN_INCREASE_ACCURACY:
1281 if ((obj->owornmask & W_RING) && u_ring)
1284 case RIN_INCREASE_DAMAGE:
1285 if ((obj->owornmask & W_RING) && u_ring)
1288 case RIN_PROTECTION:
1290 context.botl = 1; /* bot() will recalc u.uac */
1292 case HELM_OF_BRILLIANCE:
1293 if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
1299 case GAUNTLETS_OF_DEXTERITY:
1300 if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
1316 obj_resists(obj, ochance, achance)
1318 int ochance, achance; /* percent chance for ordinary objects, artifacts */
1320 if (obj->otyp == AMULET_OF_YENDOR
1321 || obj->otyp == SPE_BOOK_OF_THE_DEAD
1322 || obj->otyp == CANDELABRUM_OF_INVOCATION
1323 || obj->otyp == BELL_OF_OPENING
1324 || (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm]))) {
1327 int chance = rn2(100);
1329 return (boolean) (chance < (obj->oartifact ? achance : ochance));
1339 if (context.bypasses && obj->bypass)
1342 if (obj->oclass == WAND_CLASS)
1343 zap_odds = 3; /* half-life = 2 zaps */
1344 else if (obj->cursed)
1345 zap_odds = 3; /* half-life = 2 zaps */
1346 else if (obj->blessed)
1347 zap_odds = 12; /* half-life = 8 zaps */
1349 zap_odds = 8; /* half-life = 6 zaps */
1351 /* adjust for "large" quantities of identical things */
1355 return (boolean) !rn2(zap_odds);
1358 /* Use up at least minwt number of things made of material mat.
1359 * There's also a chance that other stuff will be used up. Finally,
1360 * there's a random factor here to keep from always using the stuff
1361 * at the top of the pile.
1364 polyuse(objhdr, mat, minwt)
1368 register struct obj *otmp, *otmp2;
1370 for (otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) {
1371 otmp2 = otmp->nexthere;
1372 if (context.bypasses && otmp->bypass)
1374 if (otmp == uball || otmp == uchain)
1376 if (obj_resists(otmp, 0, 0))
1377 continue; /* preserve unique objects */
1379 if (otmp->otyp == SCR_MAIL)
1383 if (((int) objects[otmp->otyp].oc_material == mat)
1384 == (rn2(minwt + 1) != 0)) {
1385 /* appropriately add damage to bill */
1386 if (costly_spot(otmp->ox, otmp->oy)) {
1388 addtobill(otmp, FALSE, FALSE, FALSE);
1390 (void) stolen_value(otmp, otmp->ox, otmp->oy, FALSE,
1393 if (otmp->quan < LARGEST_INT)
1394 minwt -= (int) otmp->quan;
1403 * Polymorph some of the stuff in this pile into a monster, preferably
1404 * a golem of the kind okind.
1407 create_polymon(obj, okind)
1411 struct permonst *mdat = (struct permonst *) 0;
1413 const char *material;
1416 if (context.bypasses) {
1417 /* this is approximate because the "no golems" !obj->nexthere
1418 check below doesn't understand bypassed objects; but it
1419 should suffice since bypassed objects always end up as a
1420 consecutive group at the top of their pile */
1421 while (obj && obj->bypass)
1422 obj = obj->nexthere;
1425 /* no golems if you zap only one object -- not enough stuff */
1426 if (!obj || (!obj->nexthere && obj->quan == 1L))
1429 /* some of these choices are arbitrary */
1434 pm_index = PM_IRON_GOLEM;
1436 material = "metal ";
1438 material = "
\8bà
\91®";
1445 pm_index = rn2(2) ? PM_STONE_GOLEM : PM_CLAY_GOLEM;
1447 material = "lithic ";
1449 material = "
\8dz
\95¨";
1453 /* there is no flesh type, but all food is type 0, so we use it */
1454 pm_index = PM_FLESH_GOLEM;
1456 material = "organic ";
1458 material = "
\97L
\8b@
\95¨";
1461 pm_index = PM_WOOD_GOLEM;
1465 material = "
\96Ø
\8dÞ";
1468 pm_index = PM_LEATHER_GOLEM;
1470 material = "leather ";
1475 pm_index = PM_ROPE_GOLEM;
1477 material = "cloth ";
1482 pm_index = PM_SKELETON; /* nearest thing to "bone golem" */
1486 material = "
\8d\9c";
1489 pm_index = PM_GOLD_GOLEM;
1496 pm_index = PM_GLASS_GOLEM;
1498 material = "glassy ";
1500 material = "
\83K
\83\89\83X";
1503 pm_index = PM_PAPER_GOLEM;
1505 material = "paper ";
1507 material = "
\8e\86";
1510 /* if all else fails... */
1511 pm_index = PM_STRAW_GOLEM;
1515 material = "
\95¨
\91Ì";
1520 if (!(mvitals[pm_index].mvflags & G_GENOD))
1521 mdat = &mons[pm_index];
1523 mtmp = makemon(mdat, obj->ox, obj->oy, NO_MM_FLAGS);
1524 polyuse(obj, okind, (int) mons[pm_index].cwt);
1526 if (mtmp && cansee(mtmp->mx, mtmp->my)) {
1528 pline("Some %sobjects meld, and %s arises from the pile!", material,
1531 pline("
\82¢
\82
\82Â
\82©
\82Ì%s
\82ª
\97n
\82¯
\81C
\82»
\82Ì
\8eR
\82©
\82ç%s
\82ª
\8c»
\82í
\82ê
\82½
\81I", material,
1537 /* Assumes obj is on the floor. */
1545 if (obj->otyp == SCR_MAIL)
1550 if (poly_zapped < 0) {
1551 /* some may metamorphosize */
1552 for (i = obj->quan; i; i--)
1553 if (!rn2(Luck + 45)) {
1554 poly_zapped = objects[obj->otyp].oc_material;
1559 /* if quan > 1 then some will survive intact */
1560 if (obj->quan > 1L) {
1561 if (obj->quan > LARGEST_INT)
1562 obj = splitobj(obj, (long) rnd(30000));
1564 obj = splitobj(obj, (long) rnd((int) obj->quan - 1));
1567 /* appropriately add damage to bill */
1568 if (costly_spot(obj->ox, obj->oy)) {
1570 addtobill(obj, FALSE, FALSE, FALSE);
1572 (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE);
1575 /* zap the object */
1579 /* classes of items whose current charge count carries over across polymorph
1581 static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS,
1585 * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT
1586 * then pick random object from the source's class (this is the standard
1587 * "polymorph" case). If ID is set to a specific object, inhibit fusing
1588 * n objects into 1. This could have been added as a flag, but currently
1589 * it is tied to not being the standard polymorph case. The new polymorphed
1590 * object replaces obj in its link chains. Return value is a pointer to
1593 * This should be safe to call for an object anywhere.
1601 xchar ox = 0, oy = 0;
1602 long old_wornmask, new_wornmask = 0L;
1603 boolean can_merge = (id == STRANGE_OBJECT);
1604 int obj_location = obj->where;
1606 if (obj->otyp == BOULDER)
1608 if (id == STRANGE_OBJECT) { /* preserve symbol */
1610 unsigned magic_obj = objects[obj->otyp].oc_magic;
1612 if (obj->otyp == UNICORN_HORN && obj->degraded_horn)
1614 /* Try up to 3 times to make the magic-or-not status of
1615 the new item be the same as it was for the old one. */
1616 otmp = (struct obj *) 0;
1620 otmp = mkobj(obj->oclass, FALSE);
1621 } while (--try_limit > 0
1622 && objects[otmp->otyp].oc_magic != magic_obj);
1624 /* literally replace obj with this new thing */
1625 otmp = mksobj(id, FALSE, FALSE);
1626 /* Actually more things use corpsenm but they polymorph differently */
1627 #define USES_CORPSENM(typ) \
1628 ((typ) == CORPSE || (typ) == STATUE || (typ) == FIGURINE)
1630 if (USES_CORPSENM(obj->otyp) && USES_CORPSENM(id))
1631 set_corpsenm(otmp, obj->corpsenm);
1632 #undef USES_CORPSENM
1635 /* preserve quantity */
1636 otmp->quan = obj->quan;
1637 /* preserve the shopkeepers (lack of) interest */
1638 otmp->no_charge = obj->no_charge;
1639 /* preserve inventory letter if in inventory */
1640 if (obj_location == OBJ_INVENT)
1641 otmp->invlet = obj->invlet;
1643 /* You can't send yourself 100 mail messages and then
1644 * polymorph them into useful scrolls
1646 if (obj->otyp == SCR_MAIL) {
1647 otmp->otyp = SCR_MAIL;
1652 /* avoid abusing eggs laid by you */
1653 if (obj->otyp == EGG && obj->spe) {
1654 int mnum, tryct = 100;
1656 /* first, turn into a generic egg */
1657 if (otmp->otyp == EGG)
1661 otmp->owt = weight(otmp);
1663 otmp->corpsenm = NON_PM;
1666 /* now change it into something laid by the hero */
1668 mnum = can_be_hatched(random_monster(rn2));
1669 if (mnum != NON_PM && !dead_species(mnum, TRUE)) {
1670 otmp->spe = 1; /* laid by hero */
1671 set_corpsenm(otmp, mnum); /* also sets hatch timer */
1677 /* keep special fields (including charges on wands) */
1678 if (index(charged_objs, otmp->oclass))
1679 otmp->spe = obj->spe;
1680 otmp->recharged = obj->recharged;
1682 otmp->cursed = obj->cursed;
1683 otmp->blessed = obj->blessed;
1685 if (erosion_matters(otmp)) {
1686 if (is_flammable(otmp) || is_rustprone(otmp))
1687 otmp->oeroded = obj->oeroded;
1688 if (is_corrodeable(otmp) || is_rottable(otmp))
1689 otmp->oeroded2 = obj->oeroded2;
1690 if (is_damageable(otmp))
1691 otmp->oerodeproof = obj->oerodeproof;
1694 /* Keep chest/box traps and poisoned ammo if we may */
1695 if (obj->otrapped && Is_box(otmp))
1696 otmp->otrapped = TRUE;
1698 if (obj->opoisoned && is_poisonable(otmp))
1699 otmp->opoisoned = TRUE;
1701 if (id == STRANGE_OBJECT && obj->otyp == CORPSE) {
1702 /* turn crocodile corpses into shoes */
1703 if (obj->corpsenm == PM_CROCODILE) {
1704 otmp->otyp = LOW_BOOTS;
1705 otmp->oclass = ARMOR_CLASS;
1708 otmp->oerodeproof = TRUE;
1710 otmp->cursed = FALSE;
1714 /* no box contents --KAA */
1715 if (Has_contents(otmp))
1716 delete_contents(otmp);
1718 /* 'n' merged objects may be fused into 1 object */
1719 if (otmp->quan > 1L && (!objects[otmp->otyp].oc_merge
1720 || (can_merge && otmp->quan > (long) rn2(1000))))
1723 switch (otmp->oclass) {
1725 if (otmp->otyp == MAGIC_LAMP) {
1726 otmp->otyp = OIL_LAMP;
1727 otmp->age = 1500L; /* "best" oil lamp possible */
1728 } else if (otmp->otyp == MAGIC_MARKER) {
1729 otmp->recharged = 1; /* degraded quality */
1731 /* don't care about the recharge count of other tools */
1735 while (otmp->otyp == WAN_WISHING || otmp->otyp == WAN_POLYMORPH)
1736 otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
1737 /* altering the object tends to degrade its quality
1738 (analogous to spellbook `read count' handling) */
1739 if ((int) otmp->recharged < rn2(7)) /* recharge_limit */
1744 while (otmp->otyp == POT_POLYMORPH)
1745 otmp->otyp = rnd_class(POT_GAIN_ABILITY, POT_WATER);
1749 while (otmp->otyp == SPE_POLYMORPH)
1750 otmp->otyp = rnd_class(SPE_DIG, SPE_BLANK_PAPER);
1751 /* reduce spellbook abuse; non-blank books degrade */
1752 if (otmp->otyp != SPE_BLANK_PAPER) {
1753 otmp->spestudied = obj->spestudied + 1;
1754 if (otmp->spestudied > MAX_SPELL_STUDY) {
1755 otmp->otyp = SPE_BLANK_PAPER;
1756 /* writing a new book over it will yield an unstudied
1757 one; re-polymorphing this one as-is may or may not
1758 get something non-blank */
1759 otmp->spestudied = rn2(otmp->spestudied);
1765 if (otmp->quan > (long) rnd(4)
1766 && objects[obj->otyp].oc_material == MINERAL
1767 && objects[otmp->otyp].oc_material != MINERAL) {
1768 otmp->otyp = ROCK; /* transmutation backfired */
1769 otmp->quan /= 2L; /* some material has been lost */
1774 /* update the weight */
1775 otmp->owt = weight(otmp);
1778 * ** we are now done adjusting the object (except possibly wearing it) **
1781 (void) get_obj_location(obj, &ox, &oy, BURIED_TOO | CONTAINED_TOO);
1782 old_wornmask = obj->owornmask & ~(W_ART | W_ARTI);
1783 /* swap otmp for obj */
1784 replace_object(obj, otmp);
1785 if (obj_location == OBJ_INVENT) {
1787 * We may need to do extra adjustments for the hero if we're
1788 * messing with the hero's inventory. The following calls are
1789 * equivalent to calling freeinv on obj and addinv on otmp,
1790 * while doing an in-place swap of the actual objects.
1796 * Handle polymorph of worn item. Stone-to-flesh cast on self can
1797 * affect multiple objects at once, but their new forms won't
1798 * produce any side-effects. A single worn item dipped into potion
1799 * of polymorph can produce side-effects but those won't yield out
1800 * of sequence messages because current polymorph is finished.
1803 boolean was_twohanded = bimanual(obj), was_twoweap = u.twoweap;
1805 /* wearslot() returns a mask which might have multiple bits set;
1806 narrow that down to the bit(s) currently in use */
1807 new_wornmask = wearslot(otmp) & old_wornmask;
1808 remove_worn_item(obj, TRUE);
1809 /* if the new form can be worn in the same slot, make it so */
1810 if ((new_wornmask & W_WEP) != 0L) {
1811 if (was_twohanded || !bimanual(otmp) || !uarms)
1813 if (was_twoweap && uwep && !bimanual(uwep))
1815 } else if ((new_wornmask & W_SWAPWEP) != 0L) {
1816 if (was_twohanded || !bimanual(otmp))
1818 if (was_twoweap && uswapwep)
1820 } else if ((new_wornmask & W_QUIVER) != 0L) {
1822 } else if (new_wornmask) {
1823 setworn(otmp, new_wornmask);
1824 /* set_wear() might result in otmp being destroyed if
1825 worn amulet has been turned into an amulet of change */
1827 otmp = wearmask_to_obj(new_wornmask); /* might be Null */
1829 } /* old_wornmask */
1830 } else if (obj_location == OBJ_FLOOR) {
1831 if (obj->otyp == BOULDER && otmp->otyp != BOULDER
1832 && !does_block(ox, oy, &levl[ox][oy]))
1833 unblock_point(ox, oy);
1834 else if (obj->otyp != BOULDER && otmp->otyp == BOULDER)
1835 /* (checking does_block() here would be redundant) */
1836 block_point(ox, oy);
1839 /* note: if otmp is gone, billing for it was handled by useup() */
1840 if (((otmp && !carried(otmp)) || obj->unpaid) && costly_spot(ox, oy)) {
1841 struct monst *shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE));
1843 if ((!obj->no_charge
1844 || (Has_contents(obj)
1845 && (contained_cost(obj, shkp, 0L, FALSE, FALSE) != 0L)))
1846 && inhishop(shkp)) {
1847 if (shkp->mpeaceful) {
1849 && (*in_rooms(u.ux, u.uy, 0)
1850 == *in_rooms(shkp->mx, shkp->my, 0))
1851 && !costly_spot(u.ux, u.uy)) {
1852 make_angry_shk(shkp, ox, oy);
1855 pline("%s gets angry!", Monnam(shkp));
1857 pline("%s
\82Í
\8c\83\93{
\82µ
\82½
\81I", Monnam(shkp));
1862 Norep("%s is furious!", Monnam(shkp));
1864 Norep("%s
\82Í
\93{
\82Á
\82½
\81I", Monnam(shkp));
1871 /* stone-to-flesh spell hits and maybe transforms or animates obj */
1873 stone_to_flesh_obj(obj)
1876 int res = 1; /* affected object by default */
1877 struct permonst *ptr;
1878 struct monst *mon, *shkp;
1881 boolean smell = FALSE, golem_xform = FALSE;
1883 if (objects[obj->otyp].oc_material != MINERAL
1884 && objects[obj->otyp].oc_material != GEMSTONE)
1886 /* Heart of Ahriman usually resists; ordinary items rarely do */
1887 if (obj_resists(obj, 2, 98))
1890 (void) get_obj_location(obj, &oox, &ooy, 0);
1891 /* add more if stone objects are added.. */
1892 switch (objects[obj->otyp].oc_class) {
1893 case ROCK_CLASS: /* boulders and statues */
1894 case TOOL_CLASS: /* figurines */
1895 if (obj->otyp == BOULDER) {
1896 obj = poly_obj(obj, HUGE_CHUNK_OF_MEAT);
1898 } else if (obj->otyp == STATUE || obj->otyp == FIGURINE) {
1899 ptr = &mons[obj->corpsenm];
1900 if (is_golem(ptr)) {
1901 golem_xform = (ptr != &mons[PM_FLESH_GOLEM]);
1902 } else if (vegetarian(ptr)) {
1903 /* Don't animate monsters that aren't flesh */
1904 obj = poly_obj(obj, MEATBALL);
1908 if (obj->otyp == STATUE) {
1909 /* animate_statue() forces all golems to become flesh golems */
1910 mon = animate_statue(obj, oox, ooy, ANIMATE_SPELL, (int *) 0);
1911 } else { /* (obj->otyp == FIGURINE) */
1913 ptr = &mons[PM_FLESH_GOLEM];
1914 mon = makemon(ptr, oox, ooy, NO_MINVENT);
1916 if (costly_spot(oox, ooy)
1917 && (carried(obj) ? obj->unpaid : !obj->no_charge)) {
1918 shkp = shop_keeper(*in_rooms(oox, ooy, SHOPBASE));
1919 stolen_value(obj, oox, ooy,
1920 (shkp && shkp->mpeaceful), FALSE);
1923 obj_stop_timers(obj);
1928 if (cansee(mon->mx, mon->my))
1930 pline_The("figurine %sanimates!",
1931 golem_xform ? "turns to flesh and " : "");
1933 pline_The("
\90l
\8c`
\82Í%s
\93®
\82«
\82¾
\82µ
\82½
\81I",
1934 golem_xform ? "
\90Î
\89»
\82ª
\89ð
\82¯
\82Ä" : "");
1940 /* this golem handling is redundant... */
1941 if (is_golem(ptr) && ptr != &mons[PM_FLESH_GOLEM])
1942 (void) newcham(mon, &mons[PM_FLESH_GOLEM], TRUE, FALSE);
1943 } else if ((ptr->geno & (G_NOCORPSE | G_UNIQ)) != 0) {
1944 /* didn't revive but can't leave corpse either */
1947 /* unlikely to get here since genociding monsters also
1948 sets the G_NOCORPSE flag; drop statue's contents */
1949 while ((item = obj->cobj) != 0) {
1950 bypass_obj(item); /* make stone-to-flesh miss it */
1951 obj_extract_self(item);
1952 place_object(item, oox, ooy);
1954 obj = poly_obj(obj, CORPSE);
1956 } else { /* miscellaneous tool or unexpected rock... */
1960 /* maybe add weird things to become? */
1961 case RING_CLASS: /* some of the rings are stone */
1962 obj = poly_obj(obj, MEAT_RING);
1965 case WAND_CLASS: /* marble wand */
1966 obj = poly_obj(obj, MEAT_STICK);
1969 case GEM_CLASS: /* stones & gems */
1970 obj = poly_obj(obj, MEATBALL);
1973 case WEAPON_CLASS: /* crysknife */
1981 /* non-meat eaters smell meat, meat eaters smell its flavor;
1982 monks are considered non-meat eaters regardless of behavior;
1983 other roles are non-meat eaters if they haven't broken
1984 vegetarian conduct yet (or if poly'd into non-carnivorous/
1985 non-omnivorous form, regardless of whether it's herbivorous,
1986 non-eating, or something stranger) */
1987 if (Role_if(PM_MONK) || !u.uconduct.unvegetarian
1988 || !carnivorous(youmonst.data))
1990 Norep("You smell the odor of meat.");
1992 Norep("
\93÷
\82Ì
\88«
\8fL
\82ª
\95Y
\82Á
\82½
\81D");
1995 Norep("You smell a delicious smell.");
1997 Norep("
\82·
\82Î
\82ç
\82µ
\82¢
\8d\81\82è
\82¾
\81I");
2004 * Object obj was hit by the effect of the wand/spell otmp. Return
2005 * non-zero if the wand/spell had any effect.
2009 struct obj *obj, *otmp;
2011 int res = 1; /* affected object by default */
2012 boolean learn_it = FALSE, maybelearnit;
2014 /* fundamental: a wand effect hitting itself doesn't do anything;
2015 otherwise we need to guard against accessing otmp after something
2016 strange has happened to it (along the lines of polymorph or
2017 stone-to-flesh [which aren't good examples since polymorph wands
2018 aren't affected by polymorph zaps and stone-to-flesh isn't
2019 available in wand form, but the concept still applies...]) */
2024 /* The bypass bit is currently only used as follows:
2026 * POLYMORPH - When a monster being polymorphed drops something
2027 * from its inventory as a result of the change.
2028 * If the items fall to the floor, they are not
2029 * subject to direct subsequent polymorphing
2030 * themselves on that same zap. This makes it
2031 * consistent with items that remain in the monster's
2032 * inventory. They are not polymorphed either.
2033 * UNDEAD_TURNING - When an undead creature gets killed via
2034 * undead turning, prevent its corpse from being
2035 * immediately revived by the same effect.
2036 * STONE_TO_FLESH - If a statue can't be revived, its
2037 * contents get dropped before turning it into
2038 * meat; prevent those contents from being hit.
2039 * retouch_equipment() - bypass flag is used to track which
2040 * items have been handled (bhito isn't involved).
2041 * menu_drop(), askchain() - inventory traversal where multiple
2042 * Drop can alter the invent chain while traversal
2043 * is in progress (bhito isn't involved).
2044 * destroy_item(), destroy_mitem() - inventory traversal where
2045 * item destruction can trigger drop or destruction of
2046 * other item(s) and alter the invent or mon->minvent
2047 * chain, possibly recursively.
2049 * The bypass bit on all objects is reset each turn, whenever
2050 * context.bypasses is set.
2052 * We check the obj->bypass bit above AND context.bypasses
2053 * as a safeguard against any stray occurrence left in an obj
2054 * struct someplace, although that should never happen.
2056 if (context.bypasses) {
2059 debugpline1("%s for a moment.", Tobjnam(obj, "pulsate"));
2065 * Some parts of this function expect the object to be on the floor
2066 * obj->{ox,oy} to be valid. The exception to this (so far) is
2067 * for the STONE_TO_FLESH spell.
2069 if (!(obj->where == OBJ_FLOOR || otmp->otyp == SPE_STONE_TO_FLESH))
2070 impossible("bhito: obj is not floor or Stone To Flesh spell");
2074 } else if (obj == uchain) {
2075 if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) {
2081 switch (otmp->otyp) {
2084 if (obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH
2085 || obj->otyp == POT_POLYMORPH || obj_resists(obj, 5, 95)) {
2090 u.uconduct.polypiles++;
2091 /* any saved lock context will be dangerously obsolete */
2093 (void) boxlock(obj, otmp);
2095 if (obj_shudders(obj)) {
2097 ((obj == level.objects[u.ux][u.uy]) && u.uundetected
2098 && hides_under(youmonst.data));
2100 if (cansee(obj->ox, obj->oy))
2103 /* eek - your cover might have been blown */
2105 (void) hideunder(&youmonst);
2108 obj = poly_obj(obj, STRANGE_OBJECT);
2109 newsym(obj->ox, obj->oy);
2113 /* target object has now been "seen (up close)" */
2115 if (Is_container(obj) || obj->otyp == STATUE) {
2116 obj->cknown = obj->lknown = 1;
2119 pline("%s empty.", Tobjnam(obj, "are"));
2121 pline("%s
\82Í
\8bó
\82Á
\82Û
\82¾
\81D", xname(obj));
2122 } else if (SchroedingersBox(obj)) {
2123 /* we don't want to force alive vs dead
2124 determination for Schroedinger's Cat here,
2125 so just make probing be inconclusive for it */
2126 You("aren't sure whether %s has %s or its corpse inside.",
2128 /* unfortunately, we can't tell whether rndmonnam()
2129 picks a form which can't leave a corpse */
2130 an(Hallucination ? rndmonnam((char *) 0) : "cat"));
2134 /* view contents (not recursively) */
2135 for (o = obj->cobj; o; o = o->nobj)
2136 o->dknown = 1; /* "seen", even if blind */
2137 (void) display_cinventory(obj);
2145 case SPE_FORCE_BOLT:
2146 /* learn the type if you see or hear something break
2147 (the sound could be implicit) */
2148 maybelearnit = cansee(obj->ox, obj->oy) || !Deaf;
2149 if (obj->otyp == BOULDER) {
2150 if (cansee(obj->ox, obj->oy))
2152 pline_The("boulder falls apart.");
2154 pline_The("
\8aâ
\82Í
\82Î
\82ç
\82Î
\82ç
\82É
\82È
\82Á
\82½
\81D");
2157 You_hear("a crumbling sound.");
2159 You_hear("
\89½
\82©
\82ª
\8dÓ
\82¯
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D");
2161 } else if (obj->otyp == STATUE) {
2162 if (break_statue(obj)) {
2163 if (cansee(obj->ox, obj->oy)) {
2166 pline_The("%s shatters.", rndmonnam(NULL));
2168 pline_The("%s
\82Í
\95²
\81X
\82É
\82È
\82Á
\82½
\81D", rndmonnam(NULL));
2171 pline_The("statue shatters.");
2173 pline_The("
\90Î
\91\9c\82Í
\95²
\81X
\82É
\82È
\82Á
\82½
\81D");
2176 You_hear("a crumbling sound.");
2178 You_hear("
\89½
\82©
\82ª
\8dÓ
\82¯
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D");
2183 if (context.mon_moving
2184 ? !breaks(obj, obj->ox, obj->oy)
2185 : !hero_breaks(obj, obj->ox, obj->oy, FALSE))
2186 maybelearnit = FALSE; /* nothing broke */
2188 newsym_force(oox,ooy);
2194 case WAN_CANCELLATION:
2195 case SPE_CANCELLATION:
2198 newsym(obj->ox, obj->oy); /* might change color */
2201 case SPE_DRAIN_LIFE:
2202 (void) drain_item(obj, TRUE);
2204 case WAN_TELEPORTATION:
2205 case SPE_TELEPORT_AWAY:
2208 case WAN_MAKE_INVISIBLE:
2210 case WAN_UNDEAD_TURNING:
2211 case SPE_TURN_UNDEAD:
2212 if (obj->otyp == EGG) {
2214 } else if (obj->otyp == CORPSE) {
2217 int corpsenm = corpse_revive_type(obj);
2218 char *corpsname = cxname_singular(obj);
2220 /* get corpse's location before revive() uses it up */
2221 if (!get_obj_location(obj, &ox, &oy, 0))
2222 ox = obj->ox, oy = obj->oy; /* won't happen */
2224 mtmp = revive(obj, TRUE);
2226 res = 0; /* no monster implies corpse was left intact */
2228 if (cansee(ox, oy)) {
2229 if (canspotmon(mtmp)) {
2230 pline("%s is resurrected!",
2231 upstart(noname_monnam(mtmp, ARTICLE_THE)));
2234 /* saw corpse but don't see monster: maybe
2235 mtmp is invisible, or has been placed at
2236 a different spot than <ox,oy> */
2237 if (!type_is_pname(&mons[corpsenm]))
2238 corpsname = The(corpsname);
2239 pline("%s disappears.", corpsname);
2242 /* couldn't see corpse's location */
2243 if (Role_if(PM_HEALER) && !Deaf
2244 && !nonliving(&mons[corpsenm])) {
2245 if (!type_is_pname(&mons[corpsenm]))
2246 corpsname = an(corpsname);
2248 You_hear("%s reviving.", corpsname);
2251 You_hear("a defibrillator.");
2253 You_hear("
\8f\9c\8d×
\93®
\8aí
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
2256 if (canspotmon(mtmp))
2257 /* didn't see corpse but do see monster: it
2258 has been placed somewhere other than <ox,oy>
2259 or blind hero spots it with ESP */
2261 pline("%s appears.", Monnam(mtmp));
2263 pline("%s
\82ª
\8c»
\82ê
\82½
\81D", Monnam(mtmp));
2266 exercise(A_WIS, TRUE);
2273 case SPE_WIZARD_LOCK:
2275 res = boxlock(obj, otmp);
2281 case WAN_SLOW_MONSTER: /* no effect on objects */
2282 case SPE_SLOW_MONSTER:
2283 case WAN_SPEED_MONSTER:
2286 case SPE_EXTRA_HEALING:
2289 case SPE_STONE_TO_FLESH:
2290 res = stone_to_flesh_obj(obj);
2293 impossible("What an interesting effect (%d)", otmp->otyp);
2296 /* if effect was observable then discover the wand type provided
2297 that the wand itself has been seen */
2303 /* returns nonzero if something was hit */
2305 bhitpile(obj, fhito, tx, ty, zz)
2307 int FDECL((*fhito), (OBJ_P, OBJ_P));
2311 int hitanything = 0;
2312 register struct obj *otmp, *next_obj;
2314 if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) {
2315 struct trap *t = t_at(tx, ty);
2317 /* We can't settle for the default calling sequence of
2318 bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
2319 because that last call might end up operating on our `next_obj'
2320 (below), rather than on the current object, if it happens to
2321 encounter a statue which mustn't become animated. */
2322 if (t && t->ttyp == STATUE_TRAP
2323 && activate_statue_trap(t, tx, ty, TRUE))
2328 for (otmp = level.objects[tx][ty]; otmp; otmp = next_obj) {
2329 next_obj = otmp->nexthere;
2330 /* for zap downwards, don't hit object poly'd hero is hiding under */
2331 if (zz > 0 && u.uundetected && otmp == level.objects[u.ux][u.uy]
2332 && hides_under(youmonst.data))
2335 hitanything += (*fhito)(otmp, obj);
2337 if (poly_zapped >= 0)
2338 create_polymon(level.objects[tx][ty], poly_zapped);
2344 * zappable - returns 1 if zap is available, 0 otherwise.
2345 * it removes a charge from the wand if zappable.
2346 * added by GAN 11/03/86
2350 register struct obj *wand;
2352 if (wand->spe < 0 || (wand->spe == 0 && rn2(121)))
2356 You("wrest one last charge from the worn-out wand.");
2358 You("
\8eg
\82¢
\82«
\82Á
\82½
\8fñ
\82©
\82ç
\8dÅ
\8cã
\82Ì
\97Í
\82ð
\82µ
\82Ú
\82è
\82Æ
\82Á
\82½
\81D");
2364 * zapnodir - zaps a NODIR wand/spell.
2365 * added by GAN 11/03/86
2369 register struct obj *obj;
2371 boolean known = FALSE;
2373 switch (obj->otyp) {
2379 if (lightdamage(obj, TRUE, 5))
2382 case WAN_SECRET_DOOR_DETECTION:
2383 case SPE_DETECT_UNSEEN:
2389 case WAN_CREATE_MONSTER:
2390 known = create_critters(rn2(23) ? 1 : rn1(7, 2),
2391 (struct permonst *) 0, FALSE);
2395 if (Luck + rn2(5) < 0) {
2397 pline("Unfortunately, nothing happens.");
2399 pline("
\8ec
\94O
\82È
\82ª
\82ç
\81C
\89½
\82à
\8bN
\82«
\82È
\82©
\82Á
\82½
\81D");
2404 case WAN_ENLIGHTENMENT:
2407 You_feel("self-knowledgeable...");
2409 You("
\8e©
\95ª
\8e©
\90g
\82ª
\94»
\82é
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D
\81D
\81D");
2410 display_nhwindow(WIN_MESSAGE, FALSE);
2411 enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS);
2413 pline_The("feeling subsides.");
2415 pline("
\82»
\82Ì
\8a´
\82¶
\82Í
\82È
\82
\82È
\82Á
\82½
\81D");
2416 exercise(A_WIS, TRUE);
2420 if (!objects[obj->otyp].oc_name_known)
2421 more_experienced(0, 10);
2422 /* effect was observable; discover the wand type provided
2423 that the wand itself has been seen */
2434 otmp->in_use = TRUE; /* in case losehp() is fatal */
2436 pline("%s suddenly explodes!", The(xname(otmp)));
2438 pline("%s
\82Í
\93Ë
\91R
\94\9a\94
\82µ
\82½
\81I", xname(otmp));
2439 dmg = d(otmp->spe + 2, 6);
2441 losehp(Maybe_Half_Phys(dmg), "exploding wand", KILLED_BY_AN);
2443 losehp(Maybe_Half_Phys(dmg), "
\8fñ
\82Ì
\94\9a\94
\82Å", KILLED_BY_AN);
2447 static NEARDATA const char zap_syms[] = { WAND_CLASS, 0 };
2449 /* 'z' command (or 'y' if numbed_pad==-1) */
2453 register struct obj *obj;
2456 if (check_capacity((char *) 0))
2458 obj = getobj(zap_syms, "zap");
2464 /* zappable addition done by GAN 11/03/86 */
2466 pline1(nothing_happens);
2467 else if (obj->cursed && !rn2(WAND_BACKFIRE_CHANCE)) {
2468 backfire(obj); /* the wand blows up in your face! */
2469 exercise(A_STR, FALSE);
2471 } else if (!(objects[obj->otyp].oc_dir == NODIR) && !getdir((char *) 0)) {
2474 pline("%s glows and fades.", The(xname(obj)));
2476 pline("%s
\82Í
\88ê
\8fu
\8bP
\82¢
\82½
\81D", The(xname(obj)));
2477 /* make him pay for knowing !NODIR */
2478 } else if (!u.dx && !u.dy && !u.dz
2479 && !(objects[obj->otyp].oc_dir == NODIR)) {
2480 if ((damage = zapyourself(obj, TRUE)) != 0) {
2484 Sprintf(buf, "zapped %sself with a wand", uhim());
2485 losehp(Maybe_Half_Phys(damage), buf, NO_KILLER_PREFIX);
2487 losehp(Maybe_Half_Phys(damage),
2488 "
\8e©
\95ª
\8e©
\90g
\82Ì
\8fñ
\82Ì
\97Í
\82ð
\97\81\82Ñ
\82Ä", KILLED_BY);
2492 /* Are we having fun yet?
2493 * weffects -> buzz(obj->otyp) -> zhitm (temple priest) ->
2494 * attack -> hitum -> known_hitum -> ghod_hitsu ->
2495 * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) ->
2496 * useup -> obfree -> dealloc_obj -> free(obj)
2503 if (obj && obj->spe < 0) {
2505 pline("%s to dust.", Tobjnam(obj, "turn"));
2507 pline("%s
\82Í
\82¿
\82è
\82Æ
\82È
\82Á
\82½
\81D", xname(obj));
2510 update_inventory(); /* maybe used a charge */
2515 zapyourself(obj, ordinary)
2519 boolean learn_it = FALSE;
2522 switch (obj->otyp) {
2524 case SPE_FORCE_BOLT:
2527 shieldeff(u.ux, u.uy);
2531 pline("
\83{
\83C
\83\93\81I");
2535 You("bash yourself!");
2537 You("
\8e©
\95ª
\8e©
\90g
\82ð
\91Å
\82¿
\82Â
\82¯
\82½
\81I");
2540 damage = d(1 + obj->spe, 6);
2541 exercise(A_STR, FALSE);
2547 if (!Shock_resistance) {
2549 You("shock yourself!");
2551 You("
\93d
\8c\82\82ð
\82¤
\82¯
\82½
\81I");
2553 exercise(A_CON, FALSE);
2555 shieldeff(u.ux, u.uy);
2557 You("zap yourself, but seem unharmed.");
2559 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");
2560 ugolemeffects(AD_ELEC, d(12, 6));
2562 destroy_item(WAND_CLASS, AD_ELEC);
2563 destroy_item(RING_CLASS, AD_ELEC);
2564 (void) flashburn((long) rnd(100));
2569 You("explode a fireball on top of yourself!");
2571 Your("
\93ª
\8fã
\82Å
\89Î
\82Ì
\8bÊ
\82ª
\94\9a\94
\82µ
\82½
\81I");
2572 explode(u.ux, u.uy, 11, d(6, 6), WAND_CLASS, EXPL_FIERY);
2577 if (Fire_resistance) {
2578 shieldeff(u.ux, u.uy);
2580 You_feel("rather warm.");
2582 You("
\82¿
\82å
\82Á
\82Æ
\92g
\82©
\82
\8a´
\82¶
\82½
\81D");
2583 ugolemeffects(AD_FIRE, d(12, 6));
2586 pline("You've set yourself afire!");
2588 You("
\89\8a\82É
\82Â
\82Â
\82Ü
\82ê
\82½
\81I");
2592 (void) burnarmor(&youmonst);
2593 destroy_item(SCROLL_CLASS, AD_FIRE);
2594 destroy_item(POTION_CLASS, AD_FIRE);
2595 destroy_item(SPBOOK_CLASS, AD_FIRE);
2596 destroy_item(FOOD_CLASS, AD_FIRE); /* only slime for now */
2600 case SPE_CONE_OF_COLD:
2603 if (Cold_resistance) {
2604 shieldeff(u.ux, u.uy);
2606 You_feel("a little chill.");
2608 You("
\82¿
\82å
\82Á
\82Æ
\97â
\82½
\82
\8a´
\82¶
\82½
\81D");
2609 ugolemeffects(AD_COLD, d(12, 6));
2612 You("imitate a popsicle!");
2614 You("
\83A
\83C
\83X
\83L
\83\83\83\93\83f
\81[
\82Ì
\82æ
\82¤
\82É
\82È
\82Á
\82½
\81I");
2617 destroy_item(POTION_CLASS, AD_COLD);
2620 case WAN_MAGIC_MISSILE:
2621 case SPE_MAGIC_MISSILE:
2624 shieldeff(u.ux, u.uy);
2626 pline_The("missiles bounce!");
2628 pline("
\96\82\96@
\82Ì
\96î
\82Í
\82Í
\82Ë
\82©
\82¦
\82Á
\82½
\81I");
2632 pline("Idiot! You've shot yourself!");
2634 pline("
\89½
\82â
\82Á
\82Ä
\82ñ
\82¾
\81I
\82 \82È
\82½
\82Í
\8e©
\95ª
\8e©
\90g
\82ð
\8c\82\82Á
\82½
\81I");
2646 case WAN_CANCELLATION:
2647 case SPE_CANCELLATION:
2648 (void) cancel_monst(&youmonst, obj, TRUE, TRUE, TRUE);
2651 case SPE_DRAIN_LIFE:
2652 if (!Drain_resistance) {
2653 learn_it = TRUE; /* (no effect for spells...) */
2655 losexp("life drainage");
2657 losexp("
\90¶
\96½
\97Í
\82ð
\8bz
\8eû
\82³
\82ê
\82Ä");
2659 damage = 0; /* No additional damage */
2662 case WAN_MAKE_INVISIBLE: {
2663 /* have to test before changing HInvis but must change
2664 * HInvis before doing newsym().
2666 int msg = !Invis && !Blind && !BInvis;
2668 if (BInvis && uarmc->otyp == MUMMY_WRAPPING) {
2669 /* A mummy wrapping absorbs it and protects you */
2671 You_feel("rather itchy under %s.", yname(uarmc));
2673 You("%s
\82Ì
\89º
\82ª
\83\80\83Y
\83\80\83Y
\82µ
\82½
\81D", xname(uarmc));
2676 if (ordinary || !rn2(10)) { /* permanent */
2677 HInvis |= FROMOUTSIDE;
2678 } else { /* temporary */
2679 incr_itimeout(&HInvis, d(obj->spe, 250));
2684 self_invis_message();
2689 case WAN_SPEED_MONSTER:
2690 if (!(HFast & INTRINSIC)) {
2696 You("
\93®
\82«
\82ª
\91¬
\82
\82È
\82Á
\82½
\81D");
2699 Your("quickness feels more natural.");
2701 You("
\91¬
\82³
\82É
\8aµ
\82ê
\82Ä
\82«
\82½
\81D");
2702 exercise(A_DEX, TRUE);
2704 HFast |= FROMOUTSIDE;
2710 if (Sleep_resistance) {
2711 shieldeff(u.ux, u.uy);
2713 You("don't feel sleepy!");
2715 You("
\96°
\82
\82È
\82ç
\82È
\82¢
\81I");
2718 pline_The("sleep ray hits you!");
2720 pline("
\96°
\82è
\8cõ
\90ü
\82ª
\82 \82È
\82½
\82É
\96½
\92\86\82µ
\82½
\81I");
2721 fall_asleep(-rnd(50), TRUE);
2725 case WAN_SLOW_MONSTER:
2726 case SPE_SLOW_MONSTER:
2727 if (HFast & (TIMEOUT | INTRINSIC)) {
2733 case WAN_TELEPORTATION:
2734 case SPE_TELEPORT_AWAY:
2736 /* same criteria as when mounted (zap_steed) */
2737 if ((Teleport_control && !Stunned) || !couldsee(u.ux0, u.uy0)
2738 || distu(u.ux0, u.uy0) >= 16)
2743 case SPE_FINGER_OF_DEATH:
2744 if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
2745 pline((obj->otyp == WAN_DEATH)
2747 ? "The wand shoots an apparently harmless beam at you."
2749 ? "
\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"
2751 : "You seem no deader than before.");
2753 : "
\82 \82È
\82½
\82Í
\82±
\82ê
\88È
\8fã
\8e\80\82Ë
\82È
\82¢
\82æ
\82¤
\82¾
\81D");
2758 Sprintf(killer.name, "shot %sself with a death ray", uhim());
2759 killer.format = NO_KILLER_PREFIX;
2761 Strcpy(killer.name, "
\8e©
\95ª
\82ª
\8c\82\82Á
\82½
\8e\80\82Ì
\8cõ
\90ü
\82É
\82æ
\82Á
\82Ä");
2762 killer.format = KILLED_BY;
2765 You("irradiate yourself with pure energy!");
2767 You("
\83G
\83l
\83\8b\83M
\81[
\82ð
\8e©
\95ª
\8e©
\90g
\82É
\8fÆ
\8eË
\82µ
\82½
\81D");
2771 pline("
\82 \82È
\82½
\82Í
\8e\80\82É
\82Ü
\82µ
\82½
\81D");
2772 /* They might survive with an amulet of life saving */
2775 case WAN_UNDEAD_TURNING:
2776 case SPE_TURN_UNDEAD:
2778 (void) unturn_dead(&youmonst);
2779 if (is_undead(youmonst.data)) {
2781 You_feel("frightened and %sstunned.",
2782 Stunned ? "even more " : "");
2784 You("
\8b°
\95|
\82µ%s
\82
\82ç
\82
\82ç
\82µ
\82½
\81D",
2785 Stunned ? "
\82³
\82ç
\82É" : "");
2787 make_stunned((HStun & TIMEOUT) + (long) rnd(30), FALSE);
2790 You("shudder in dread.");
2792 You("
\8b°
\95|
\82Å
\90k
\82¦
\82½
\81D");
2795 case SPE_EXTRA_HEALING:
2796 learn_it = TRUE; /* (no effect for spells...) */
2797 healup(d(6, obj->otyp == SPE_EXTRA_HEALING ? 8 : 4), 0, FALSE,
2798 (obj->blessed || obj->otyp == SPE_EXTRA_HEALING));
2800 You_feel("%sbetter.", obj->otyp == SPE_EXTRA_HEALING ? "much " : "");
2802 You("%s
\8bC
\95ª
\82ª
\82æ
\82
\82È
\82Á
\82½
\81D", obj->otyp == SPE_EXTRA_HEALING ? "
\82Æ
\82Ä
\82à" : "");
2804 case WAN_LIGHT: /* (broken wand) */
2805 /* assert( !ordinary ); */
2806 damage = d(obj->spe, 25);
2808 case EXPENSIVE_CAMERA:
2811 damage = lightdamage(obj, ordinary, damage);
2813 if (flashburn((long) damage))
2815 damage = 0; /* reset */
2823 if (u.utrap) { /* escape web or bear trap */
2824 (void) openholdingtrap(&youmonst, &learn_it);
2827 /* unlock carried boxes */
2828 for (otmp = invent; otmp; otmp = otmp->nobj)
2830 (void) boxlock(otmp, obj);
2831 /* trigger previously escaped trapdoor */
2832 (void) openfallingtrap(&youmonst, TRUE, &learn_it);
2836 case SPE_WIZARD_LOCK:
2838 (void) closeholdingtrap(&youmonst, &learn_it);
2843 case SPE_DETECT_UNSEEN:
2849 for (otmp = invent; otmp; otmp = otmp->nobj) {
2851 if (Is_container(otmp) || otmp->otyp == STATUE) {
2853 if (!SchroedingersBox(otmp))
2861 case SPE_STONE_TO_FLESH: {
2862 struct obj *otmp, *onxt;
2865 if (u.umonnum == PM_STONE_GOLEM) {
2867 (void) polymon(PM_FLESH_GOLEM);
2871 fix_petrification(); /* saved! */
2873 /* but at a cost.. */
2874 for (otmp = invent; otmp; otmp = onxt) {
2876 if (bhito(otmp, obj))
2880 * It is possible that we can now merge some inventory.
2881 * Do a highly paranoid merge. Restart from the beginning
2886 for (otmp = invent; !didmerge && otmp; otmp = otmp->nobj)
2887 for (onxt = otmp->nobj; onxt; onxt = onxt->nobj)
2888 if (merged(&otmp, &onxt)) {
2896 impossible("zapyourself: object %d used?", obj->otyp);
2899 /* if effect was observable then discover the wand type provided
2900 that the wand itself has been seen */
2906 /* called when poly'd hero uses breath attack against self */
2909 struct attack *mattk;
2911 int dtyp = 20 + mattk->adtyp - 1; /* breath by hero */
2912 const char *fltxt = flash_types[dtyp]; /* blast of <something> */
2914 zhitu(dtyp, mattk->damn, fltxt, u.ux, u.uy);
2917 /* light damages hero in gremlin form */
2919 lightdamage(obj, ordinary, amt)
2920 struct obj *obj; /* item making light (fake book if spell) */
2921 boolean ordinary; /* wand/camera zap vs wand destruction */
2922 int amt; /* pseudo-damage used to determine blindness duration */
2928 if (dmg && youmonst.data == &mons[PM_GREMLIN]) {
2929 /* reduce high values (from destruction of wand with many charges) */
2932 dmg = 10 + rnd(dmg - 10);
2936 pline("Ow, that light hurts%c", (dmg > 2 || u.mh <= 5) ? '!' : '.');
2938 pline("
\82¨
\82í
\81C
\8cõ
\82ª
\92É
\82¢%s", (dmg > 2 || u.mh <= 5) ? "
\81I" : "
\81D");
2939 /* [composing killer/reason is superfluous here; if fatal, cause
2940 of death will always be "killed while stuck in creature form"] */
2942 if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS)
2943 ordinary = FALSE; /* say blasted rather than zapped */
2945 how = (obj->oclass != SPBOOK_CLASS)
2946 ? (const char *) ansimpleoname(obj)
2950 : "
\8cõ
\82Ì
\96\82\96@";
2952 Sprintf(buf, "%s %sself with %s", ordinary ? "zapped" : "blasted",
2955 Sprintf(buf, "
\8e©
\95ª
\82Å%s
\82ð
\97\81\82Ñ
\82Ä", how);
2957 /* might rehumanize(); could be fatal, but only for Unchanging */
2959 losehp(Maybe_Half_Phys(dmg), buf, NO_KILLER_PREFIX);
2961 losehp(Maybe_Half_Phys(dmg), buf, KILLED_BY);
2967 /* light[ning] causes blindness */
2972 if (!resists_blnd(&youmonst)) {
2973 You(are_blinded_by_the_flash);
2974 make_blinded(duration, FALSE);
2976 Your1(vision_clears);
2982 /* you've zapped a wand downwards while riding
2983 * Return TRUE if the steed was hit by the wand.
2984 * Return FALSE if the steed was not hit by the wand.
2988 struct obj *obj; /* wand or spell */
2990 int steedhit = FALSE;
2992 bhitpos.x = u.usteed->mx, bhitpos.y = u.usteed->my;
2994 switch (obj->otyp) {
2996 * Wands that are allowed to hit the steed
2997 * Carefully test the results of any that are
2998 * moved here from the bottom section.
3001 probe_monster(u.usteed);
3005 case WAN_TELEPORTATION:
3006 case SPE_TELEPORT_AWAY:
3007 /* you go together */
3009 /* same criteria as when unmounted (zapyourself) */
3010 if ((Teleport_control && !Stunned) || !couldsee(u.ux0, u.uy0)
3011 || distu(u.ux0, u.uy0) >= 16)
3016 /* Default processing via bhitm() for these */
3017 case SPE_CURE_SICKNESS:
3018 case WAN_MAKE_INVISIBLE:
3019 case WAN_CANCELLATION:
3020 case SPE_CANCELLATION:
3024 case SPE_FORCE_BOLT:
3025 case WAN_SLOW_MONSTER:
3026 case SPE_SLOW_MONSTER:
3027 case WAN_SPEED_MONSTER:
3029 case SPE_EXTRA_HEALING:
3030 case SPE_DRAIN_LIFE:
3033 (void) bhitm(u.usteed, obj);
3045 * cancel a monster (possibly the hero). inventory is cancelled only
3046 * if the monster is zapping itself directly, since otherwise the
3047 * effect is too strong. currently non-hero monsters do not zap
3048 * themselves with cancellation.
3051 cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel)
3052 register struct monst *mdef;
3053 register struct obj *obj;
3054 boolean youattack, allow_cancel_kill, self_cancel;
3056 boolean youdefend = (mdef == &youmonst);
3057 static const char writing_vanishes[] =
3059 "Some writing vanishes from %s head!";
3061 "
\89½
\82©
\82Ì
\95¶
\8e\9a\82ª%s
\82Ì
\93ª
\82©
\82ç
\8fÁ
\82¦
\82½
\81I";
3063 static const char your[] = "your"; /* should be extern */
3065 static const char your[] = "
\82 \82È
\82½"; /* should be extern */
3068 if (youdefend ? (!youattack && Antimagic)
3069 : resist(mdef, obj->oclass, 0, NOTELL))
3070 return FALSE; /* resisted cancellation */
3072 if (self_cancel) { /* 1st cancel inventory */
3075 for (otmp = (youdefend ? invent : mdef->minvent); otmp;
3079 context.botl = 1; /* potential AC change */
3084 /* now handle special cases */
3086 if (Upolyd) { /* includes lycanthrope in creature form */
3088 * Return to normal form unless Unchanging.
3089 * Hero in clay golem form dies if Unchanging.
3090 * Does not cure lycanthropy or stop timed random polymorph.
3092 if (u.umonnum == PM_CLAY_GOLEM) {
3094 pline(writing_vanishes, your);
3095 else /* note: "dark" rather than "heavy" is intentional... */
3096 You_feel("%s headed.", Hallucination ? "dark" : "light");
3097 u.mh = 0; /* fatal; death handled by rehumanize() */
3099 if (Unchanging && u.mh > 0)
3101 Your("amulet grows hot for a moment, then cools.");
3103 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");
3109 /* force shapeshifter into its base form */
3110 if (M_AP_TYPE(mdef) != M_AP_NOTHING)
3112 /* [not 'else if'; chameleon might have been hiding as a mimic] */
3113 if (mdef->cham >= LOW_PM) {
3114 /* note: newcham() uncancels shapechangers (resets m->mcan
3115 to 0), but only for shapechangers whose m->cham is already
3116 NON_PM and we just verified that it's LOW_PM or higher */
3117 newcham(mdef, &mons[mdef->cham], FALSE, FALSE);
3118 mdef->cham = NON_PM; /* cancelled shapeshifter can't shift */
3120 if (is_were(mdef->data) && !is_human(mdef->data))
3123 if (mdef->data == &mons[PM_CLAY_GOLEM]) {
3124 if (canseemon(mdef))
3126 pline(writing_vanishes, s_suffix(mon_nam(mdef)));
3128 pline(writing_vanishes, mon_nam(mdef));
3130 /* !allow_cancel_kill is for Magicbane, where clay golem
3131 will be killed somewhere back up the call/return chain... */
3132 if (allow_cancel_kill) {
3136 monkilled(mdef, "", AD_SPEL);
3143 /* you've zapped an immediate type wand up or down */
3146 struct obj *obj; /* wand or spell */
3148 boolean striking = FALSE, disclose = FALSE;
3149 int x, y, xx, yy, ptmp;
3155 /* some wands have special effects other than normal bhitpile */
3156 /* drawbridge might change <u.ux,u.uy> */
3157 x = xx = u.ux; /* <x,y> is zap location */
3158 y = yy = u.uy; /* <xx,yy> is drawbridge (portcullis) position */
3159 ttmp = t_at(x, y); /* trap if there is one */
3161 switch (obj->otyp) {
3166 You("probe towards the %s.", ceiling(x, y));
3168 You("
\8fã
\95û
\82Ì%s
\82ð
\92²
\82×
\82½
\81D", ceiling(x,y));
3170 ptmp += bhitpile(obj, bhito, x, y, u.dz);
3172 You("probe beneath the %s.", surface(x, y));
3174 You("
\89º
\95û
\82Ì%s
\82ð
\92²
\82×
\82½
\81D", surface(x,y));
3175 ptmp += display_binventory(x, y, TRUE);
3179 Your("probe reveals nothing.");
3181 pline("
\92²
\8d¸
\82Ì
\8c\8b\89Ê
\89½
\82à
\82Å
\82Ä
\82±
\82È
\82©
\82Á
\82½
\81D");
3182 return TRUE; /* we've done our own bhitpile */
3185 /* up or down, but at closed portcullis only */
3186 if (is_db_wall(x, y) && find_drawbridge(&xx, &yy)) {
3187 open_drawbridge(xx, yy);
3189 } else if (u.dz > 0 && (x == xdnstair && y == ydnstair)
3190 /* can't use the stairs down to quest level 2 until
3191 leader "unlocks" them; give feedback if you try */
3192 && on_level(&u.uz, &qstart_level) && !ok_to_quest()) {
3194 pline_The("stairs seem to ripple momentarily.");
3196 pline("
\8aK
\92i
\82ª
\88ê
\8fu
\97h
\82ê
\82½
\82æ
\82¤
\82É
\8c©
\82¦
\82½
\81D");
3199 /* down will release you from bear trap or web */
3200 if (u.dz > 0 && u.utrap) {
3201 (void) openholdingtrap(&youmonst, &disclose);
3202 /* down will trigger trapdoor, hole, or [spiked-] pit */
3203 } else if (u.dz > 0 && !u.utrap) {
3204 (void) openfallingtrap(&youmonst, FALSE, &disclose);
3208 case SPE_FORCE_BOLT:
3212 case SPE_WIZARD_LOCK:
3213 /* down at open bridge or up or down at open portcullis */
3214 if (((levl[x][y].typ == DRAWBRIDGE_DOWN)
3216 : (is_drawbridge_wall(x, y) >= 0 && !is_db_wall(x, y)))
3217 && find_drawbridge(&xx, &yy)) {
3219 close_drawbridge(xx, yy);
3221 destroy_drawbridge(xx, yy);
3223 } else if (striking && u.dz < 0 && rn2(3) && !Is_airlevel(&u.uz)
3224 && !Is_waterlevel(&u.uz) && !Underwater
3225 && !Is_qstart(&u.uz)) {
3227 /* similar to zap_dig() */
3229 pline("A rock is dislodged from the %s and falls on your %s.",
3230 ceiling(x, y), body_part(HEAD));
3232 pline("%s
\82©
\82ç
\8aâ
\82ª
\97\8e\82¿
\82Ä
\82 \82È
\82½
\82Ì%s
\82É
\96½
\92\86\82µ
\82½
\81D",
3233 ceiling(x, y), body_part(HEAD));
3235 dmg = rnd((uarmh && is_metallic(uarmh)) ? 2 : 6);
3237 losehp(Maybe_Half_Phys(dmg), "falling rock", KILLED_BY_AN);
3239 losehp(Maybe_Half_Phys(dmg), "
\97\8e\8aâ
\82Å", KILLED_BY_AN);
3240 if ((otmp = mksobj_at(ROCK, x, y, FALSE, FALSE)) != 0) {
3241 (void) xname(otmp); /* set dknown, maybe bknown */
3245 } else if (u.dz > 0 && ttmp) {
3246 if (!striking && closeholdingtrap(&youmonst, &disclose)) {
3247 ; /* now stuck in web or bear trap */
3248 } else if (striking && ttmp->ttyp == TRAPDOOR) {
3249 /* striking transforms trapdoor into hole */
3250 if (Blind && !ttmp->tseen) {
3252 pline("%s beneath you shatters.", Something);
3254 pline("
\82 \82È
\82½
\82Ì
\89º
\82É
\82 \82é
\89½
\82©
\82ª
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D");
3255 } else if (!ttmp->tseen) { /* => !Blind */
3257 pline("There's a trapdoor beneath you; it shatters.");
3259 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");
3262 pline("The trapdoor beneath you shatters.");
3264 pline("
\82 \82È
\82½
\82Ì
\89º
\82É
\82 \82é
\97\8e\82µ
\94à
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D");
3270 /* might fall down hole */
3272 } else if (!striking && ttmp->ttyp == HOLE) {
3273 /* locking transforms hole into trapdoor */
3274 ttmp->ttyp = TRAPDOOR;
3275 if (Blind || !ttmp->tseen) {
3277 pline("Some %s swirls beneath you.",
3278 is_ice(x, y) ? "frost" : "dust");
3280 pline("
\82 \82È
\82½
\82Ì
\89º
\82Å%s
\82ª
\82¤
\82¸
\82ð
\8aª
\82
\82Ì
\82ª
\8c©
\82¦
\82½
\81D",
3281 is_ice(x,y) ? "
\91\9a" : "
\82Ù
\82±
\82è");
3287 pline("A trapdoor appears beneath you.");
3289 pline("
\82 \82È
\82½
\82Ì
\89º
\82É
\97\8e\82µ
\94à
\82ª
\82 \82ç
\82í
\82ê
\82½
\81D");
3292 /* hadn't fallen down hole; won't fall now */
3296 case SPE_STONE_TO_FLESH:
3297 if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || Underwater
3298 || (Is_qstart(&u.uz) && u.dz < 0)) {
3299 pline1(nothing_happens);
3300 } else if (u.dz < 0) { /* we should do more... */
3302 pline("Blood drips on your %s.", body_part(FACE));
3304 pline("
\8c\8c\82ª
\82 \82È
\82½
\82Ì%s
\82Ö
\82µ
\82½
\82½
\82è
\97\8e\82¿
\82Ä
\82«
\82½
\81D", body_part(FACE));
3305 } else if (u.dz > 0 && !OBJ_AT(u.ux, u.uy)) {
3307 Print this message only if there wasn't an engraving
3308 affected here. If water or ice, act like waterlevel case.
3310 e = engr_at(u.ux, u.uy);
3311 if (!(e && e->engr_type == ENGRAVE)) {
3312 if (is_pool(u.ux, u.uy) || is_ice(u.ux, u.uy))
3313 pline1(nothing_happens);
3316 pline("Blood %ss %s your %s.",
3317 is_lava(u.ux, u.uy) ? "boil" : "pool",
3318 Levitation ? "beneath" : "at",
3319 makeplural(body_part(FOOT)));
3322 makeplural(body_part(FOOT)),
3323 Levitation ? "
\82Ì
\89º" : "
\8c³",
3324 is_lava(u.ux, u.uy) ?
3325 "
\82Å
\8c\8c\82ª
\95¦
\93«
\82µ
\82½" : "
\82É
\8c\8c\82¾
\82Ü
\82è
\82ª
\8fo
\97\88\82½");
3335 /* zapping downward */
3336 (void) bhitpile(obj, bhito, x, y, u.dz);
3338 /* subset of engraving effects; none sets `disclose' */
3339 if ((e = engr_at(x, y)) != 0 && e->engr_type != HEADSTONE) {
3340 switch (obj->otyp) {
3344 make_engr_at(x, y, random_engraving(buf), moves, (xchar) 0);
3346 case WAN_CANCELLATION:
3347 case SPE_CANCELLATION:
3348 case WAN_MAKE_INVISIBLE:
3351 case WAN_TELEPORTATION:
3352 case SPE_TELEPORT_AWAY:
3355 case SPE_STONE_TO_FLESH:
3356 if (e->engr_type == ENGRAVE) {
3357 /* only affects things in stone */
3359 pline_The(Hallucination
3360 ? "floor runs like butter!"
3361 : "edges on the floor get smoother.");
3364 ? "
\8f°
\82ª
\83o
\83^
\81[
\82Ì
\82æ
\82¤
\82É
\91\96\82Á
\82Ä
\82¢
\82Á
\82½
\81I"
3365 : "
\8f°
\82Ì
\89\8f\82ª
\82È
\82ß
\82ç
\82©
\82É
\82È
\82Á
\82½
\81D");
3367 wipe_engr_at(x, y, d(2, 4), TRUE);
3371 case SPE_FORCE_BOLT:
3372 wipe_engr_at(x, y, d(2, 4), TRUE);
3378 } else if (u.dz < 0) {
3379 /* zapping upward */
3381 /* game flavor: if you're hiding under "something"
3382 * a zap upward should hit that "something".
3384 if (u.uundetected && hides_under(youmonst.data)) {
3386 otmp = level.objects[u.ux][u.uy];
3389 hitit = bhito(otmp, obj);
3391 (void) hideunder(&youmonst);
3400 /* used by do_break_wand() was well as by weffects() */
3410 /* if do_osshock() set obj_zapped while polying, give a message now */
3413 You_feel("shuddering vibrations.");
3415 You("
\82¼
\82Á
\82Æ
\82·
\82é
\90U
\93®
\82ð
\8a´
\82¶
\82½
\81D");
3419 /* called for various wand and spell effects - M. Stephenson */
3424 int otyp = obj->otyp;
3425 boolean disclose = FALSE, was_unkn = !objects[otyp].oc_name_known;
3427 exercise(A_WIS, TRUE);
3428 if (u.usteed && (objects[otyp].oc_dir != NODIR) && !u.dx && !u.dy
3429 && (u.dz > 0) && zap_steed(obj)) {
3431 } else if (objects[otyp].oc_dir == IMMEDIATE) {
3432 zapsetup(); /* reset obj_zapped */
3434 (void) bhitm(u.ustuck, obj);
3435 /* [how about `bhitpile(u.ustuck->minvent)' effect?] */
3437 disclose = zap_updown(obj);
3439 (void) bhit(u.dx, u.dy, rn1(8, 6), ZAPPED_WAND, bhitm, bhito,
3442 zapwrapup(); /* give feedback for obj_zapped */
3444 } else if (objects[otyp].oc_dir == NODIR) {
3448 /* neither immediate nor directionless */
3450 if (otyp == WAN_DIGGING || otyp == SPE_DIG)
3452 else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH)
3453 buzz(otyp - SPE_MAGIC_MISSILE + 10, u.ulevel / 2 + 1, u.ux, u.uy,
3455 else if (otyp >= WAN_MAGIC_MISSILE && otyp <= WAN_LIGHTNING)
3456 buzz(otyp - WAN_MAGIC_MISSILE,
3457 (otyp == WAN_MAGIC_MISSILE) ? 2 : 6, u.ux, u.uy, u.dx, u.dy);
3459 impossible("weffects: unexpected spell or wand");
3465 more_experienced(0, 10);
3470 /* augment damage for a spell dased on the hero's intelligence (and level) */
3472 spell_damage_bonus(dmg)
3473 int dmg; /* base amount to be adjusted by bonus or penalty */
3475 int intell = ACURR(A_INT);
3477 /* Punish low intelligence before low level else low intelligence
3478 gets punished only when high level */
3480 /* -3 penalty, but never reduce combined amount below 1
3481 (if dmg is 0 for some reason, we're careful to leave it there) */
3483 dmg = (dmg <= 3) ? 1 : dmg - 3;
3484 } else if (intell <= 13 || u.ulevel < 5)
3485 ; /* no bonus or penalty; dmg remains same */
3486 else if (intell <= 18)
3488 else if (intell <= 24 || u.ulevel < 14)
3491 dmg += 3; /* Int 25 */
3497 * Generate the to hit bonus for a spell. Based on the hero's skill in
3498 * spell class and dexterity.
3501 spell_hit_bonus(skill)
3505 int dex = ACURR(A_DEX);
3507 switch (P_SKILL(spell_skilltype(skill))) {
3508 case P_ISRESTRICTED:
3530 /* Will change when print stuff below removed */
3533 /* Even increment for dextrous heroes (see weapon.c abon) */
3534 hit_bon += dex - 14;
3543 /* force == 0 occurs e.g. with sleep ray */
3544 /* note that large force is usual with wands so that !! would
3545 require information about hand/weapon/wand */
3547 return (const char *) ((force < 0) ? "?" : (force <= 4) ? "." : "!");
3549 return (const char *) ((force < 0) ? "
\81H" : (force <= 4) ? "
\81D" : "
\81I");
3553 hit(str, mtmp, force)
3556 const char *force; /* usually either "." or "!" */
3558 if ((!cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)
3559 && !(u.uswallow && mtmp == u.ustuck)) || !flags.verbose)
3561 pline("%s %s it.", The(str), vtense(str, "hit"));
3563 pline("%s
\82Í
\89½
\82©
\82É
\96½
\92\86\82µ
\82½
\81D", str);
3566 pline("%s %s %s%s", The(str), vtense(str, "hit"),
3567 mon_nam(mtmp), force);
3569 pline("%s
\82Í%s
\82É
\96½
\92\86\82µ
\82½%s", str,
3570 mon_nam(mtmp), force);
3576 register const char *str;
3577 register struct monst *mtmp;
3581 "%s %s %s.", The(str), vtense(str, "miss"),
3582 ((cansee(bhitpos.x, bhitpos.y) || canspotmon(mtmp)) && flags.verbose)
3587 "%s
\82Ì%s
\82Ö
\82Ì
\8dU
\8c\82\82Í
\82Í
\82¸
\82ê
\82½
\81D", str,
3588 ((cansee(bhitpos.x,bhitpos.y) || canspotmon(mtmp)) && flags.verbose)
3595 skiprange(range, skipstart, skipend)
3596 int range, *skipstart, *skipend;
3598 int tr = (range / 4);
3599 int tmp = range - ((tr > 0) ? rnd(tr) : 0);
3602 *skipend = tmp - ((tmp / 4) * rnd(3));
3603 if (*skipend >= tmp)
3608 * Called for the following distance effects:
3609 * when a weapon is thrown (weapon == THROWN_WEAPON)
3610 * when an object is kicked (KICKED_WEAPON)
3611 * when an IMMEDIATE wand is zapped (ZAPPED_WAND)
3612 * when a light beam is flashed (FLASHED_LIGHT)
3613 * when a mirror is applied (INVIS_BEAM)
3614 * A thrown/kicked object falls down at end of its range or when a monster
3615 * is hit. The variable 'bhitpos' is set to the final position of the weapon
3616 * thrown/zapped. The ray of a wand may affect (by calling a provided
3617 * function) several objects and monsters on its path. The return value
3618 * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer.
3620 * Thrown and kicked objects (THROWN_WEAPON or KICKED_WEAPON) may be
3621 * destroyed and *pobj set to NULL to indicate this.
3623 * Check !u.uswallow before calling bhit().
3624 * This function reveals the absence of a remembered invisible monster in
3625 * necessary cases (throwing or kicking weapons). The presence of a real
3626 * one is revealed for a weapon, but if not a weapon is left up to fhitm().
3629 bhit(ddx, ddy, range, weapon, fhitm, fhito, pobj)
3630 register int ddx, ddy, range; /* direction and range */
3631 enum bhit_call_types weapon; /* defined in hack.h */
3632 int FDECL((*fhitm), (MONST_P, OBJ_P)), /* fns called when mon/obj hit */
3633 FDECL((*fhito), (OBJ_P, OBJ_P));
3634 struct obj **pobj; /* object tossed/used, set to NULL
3635 * if object is destroyed */
3638 struct obj *obj = *pobj;
3640 boolean shopdoor = FALSE, point_blank = TRUE;
3641 boolean in_skip = FALSE, allow_skip = FALSE;
3642 boolean tethered_weapon = FALSE;
3643 int skiprange_start = 0, skiprange_end = 0, skipcount = 0;
3645 if (weapon == KICKED_WEAPON) {
3646 /* object starts one square in front of player */
3647 bhitpos.x = u.ux + ddx;
3648 bhitpos.y = u.uy + ddy;
3655 if (weapon == THROWN_WEAPON && obj && obj->otyp == ROCK) {
3656 skiprange(range, &skiprange_start, &skiprange_end);
3657 allow_skip = !rn2(3);
3660 if (weapon == FLASHED_LIGHT) {
3661 tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam));
3662 } else if (weapon == THROWN_TETHERED_WEAPON && obj) {
3663 tethered_weapon = TRUE;
3664 weapon = THROWN_WEAPON; /* simplify if's that follow below */
3665 tmp_at(DISP_TETHER, obj_to_glyph(obj, rn2_on_display_rng));
3666 } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM)
3667 tmp_at(DISP_FLASH, obj_to_glyph(obj, rn2_on_display_rng));
3669 while (range-- > 0) {
3683 if (is_pick(obj) && inside_shop(x, y)
3684 && (mtmp = shkcatch(obj, x, y)) != 0) {
3685 tmp_at(DISP_END, 0);
3689 typ = levl[bhitpos.x][bhitpos.y].typ;
3691 /* iron bars will block anything big enough */
3692 if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
3694 && hits_bars(pobj, x - ddx, y - ddy, bhitpos.x, bhitpos.y,
3695 point_blank ? 0 : !rn2(5), 1)) {
3696 /* caveat: obj might now be null... */
3703 if (weapon == ZAPPED_WAND && find_drawbridge(&x, &y)) {
3704 boolean learn_it = FALSE;
3706 switch (obj->otyp) {
3709 if (is_db_wall(bhitpos.x, bhitpos.y)) {
3710 if (cansee(x, y) || cansee(bhitpos.x, bhitpos.y))
3712 open_drawbridge(x, y);
3716 case SPE_WIZARD_LOCK:
3717 if ((cansee(x, y) || cansee(bhitpos.x, bhitpos.y))
3718 && levl[x][y].typ == DRAWBRIDGE_DOWN)
3720 close_drawbridge(x, y);
3723 case SPE_FORCE_BOLT:
3724 if (typ != DRAWBRIDGE_UP)
3725 destroy_drawbridge(x, y);
3733 mtmp = m_at(bhitpos.x, bhitpos.y);
3738 * skiprange_start is only set if this is a thrown rock
3740 if (skiprange_start && (range == skiprange_start) && allow_skip) {
3741 if (is_pool(bhitpos.x, bhitpos.y) && !mtmp) {
3745 pline("%s %s%s.", Yname2(obj), otense(obj, "skip"),
3746 skipcount ? " again" : "");
3748 pline("%s
\82Í%s
\92µ
\82Ë
\82½
\81D", Yname2(obj),
3749 skipcount ? "
\8dÄ
\82Ñ" : "");
3753 You_hear("%s skip.", yname(obj));
3755 You_hear("%s
\82ª
\92µ
\82Ë
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D", yname(obj));
3757 } else if (skiprange_start > skiprange_end + 1) {
3762 if (range <= skiprange_end) {
3764 if (range > 3) /* another bounce? */
3765 skiprange(range, &skiprange_start, &skiprange_end);
3766 } else if (mtmp && M_IN_WATER(mtmp->data)) {
3767 if ((!Blind && canseemon(mtmp)) || sensemon(mtmp))
3769 pline("%s %s over %s.", Yname2(obj), otense(obj, "pass"),
3772 pline("%s
\82Í%s
\82ð
\94ò
\82Ñ
\89z
\82¦
\82½
\81D", Yname2(obj),
3778 if (mtmp && !(in_skip && M_IN_WATER(mtmp->data))) {
3779 notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
3780 if (weapon == FLASHED_LIGHT) {
3781 /* FLASHED_LIGHT hitting invisible monster should
3782 pass through instead of stop so we call
3783 flash_hits_mon() directly rather than returning
3784 mtmp back to caller. That allows the flash to
3785 keep on going. Note that we use mtmp->minvis
3786 not canspotmon() because it makes no difference
3787 whether the hero can see the monster or not. */
3789 obj->ox = u.ux, obj->oy = u.uy;
3790 (void) flash_hits_mon(mtmp, obj);
3792 tmp_at(DISP_END, 0);
3793 return mtmp; /* caller will call flash_hits_mon */
3795 } else if (weapon == INVIS_BEAM) {
3796 /* Like FLASHED_LIGHT, INVIS_BEAM should continue
3797 through invisible targets; unlike it, we aren't
3798 prepared for multiple hits so just get first one
3799 that's either visible or could see its invisible
3800 self. [No tmp_at() cleanup is needed here.] */
3801 if (!mtmp->minvis || perceives(mtmp->data))
3803 } else if (weapon != ZAPPED_WAND) {
3805 /* THROWN_WEAPON, KICKED_WEAPON */
3806 if (!tethered_weapon)
3807 tmp_at(DISP_END, 0);
3809 if (cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp))
3810 map_invisible(bhitpos.x, bhitpos.y);
3814 (*fhitm)(mtmp, obj);
3818 if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING
3819 && glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) {
3820 unmap_object(bhitpos.x, bhitpos.y);
3825 if (bhitpile(obj, fhito, bhitpos.x, bhitpos.y, 0))
3828 if (weapon == KICKED_WEAPON
3829 && ((obj->oclass == COIN_CLASS
3830 && OBJ_AT(bhitpos.x, bhitpos.y))
3831 || ship_object(obj, bhitpos.x, bhitpos.y,
3832 costly_spot(bhitpos.x, bhitpos.y)))) {
3833 tmp_at(DISP_END, 0);
3834 return (struct monst *) 0;
3837 if (weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) {
3838 switch (obj->otyp) {
3843 case SPE_WIZARD_LOCK:
3844 case SPE_FORCE_BOLT:
3845 if (doorlock(obj, bhitpos.x, bhitpos.y)) {
3846 if (cansee(bhitpos.x, bhitpos.y)
3847 || (obj->otyp == WAN_STRIKING && !Deaf))
3849 if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN
3850 && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) {
3852 add_damage(bhitpos.x, bhitpos.y, SHOP_DOOR_COST);
3858 if (!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) {
3863 if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) {
3864 /* 'I' present but no monster: erase */
3865 /* do this before the tmp_at() */
3866 if (glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)
3868 unmap_object(bhitpos.x, bhitpos.y);
3871 tmp_at(bhitpos.x, bhitpos.y);
3873 /* kicked objects fall in pools */
3874 if ((weapon == KICKED_WEAPON)
3875 && (is_pool(bhitpos.x, bhitpos.y)
3876 || is_lava(bhitpos.x, bhitpos.y)))
3878 if (IS_SINK(typ) && weapon != FLASHED_LIGHT)
3879 break; /* physical objects fall onto sink */
3881 /* limit range of ball so hero won't make an invalid move */
3882 if (weapon == THROWN_WEAPON && range > 0
3883 && obj->otyp == HEAVY_IRON_BALL) {
3887 if ((bobj = sobj_at(BOULDER, x, y)) != 0) {
3890 pline("%s hits %s.", The(distant_name(obj, xname)),
3893 pline("%s
\82Í%s
\82É
\96½
\92\86\82µ
\82½
\81D", distant_name(obj, xname),
3897 } else if (obj == uball) {
3898 if (!test_move(x - ddx, y - ddy, ddx, ddy, TEST_MOVE)) {
3899 /* nb: it didn't hit anything directly */
3902 pline("%s jerks to an abrupt halt.",
3903 The(distant_name(obj, xname))); /* lame */
3905 pline("%s
\82Í
\82Æ
\82Â
\82º
\82ñ
\83K
\83N
\83\93\82Æ
\8e~
\82Ü
\82Á
\82½
\81D",
3906 distant_name(obj, xname)); /* lame */
3909 } else if (Sokoban && (t = t_at(x, y)) != 0
3910 && (is_pit(t->ttyp) || is_hole(t->ttyp))) {
3911 /* hero falls into the trap, so ball stops */
3917 /* thrown/kicked missile has moved away from its starting spot */
3918 point_blank = FALSE; /* affects passing through iron bars */
3921 if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM && !tethered_weapon)
3922 tmp_at(DISP_END, 0);
3926 pay_for_damage("destroy", FALSE);
3928 pay_for_damage("
\94j
\89ó
\82·
\82é", FALSE);
3930 return (struct monst *) 0;
3933 /* process thrown boomerang, which travels a curving path...
3934 * A multi-shot volley ought to have all missiles in flight at once,
3935 * but we're called separately for each one. We terminate the volley
3936 * early on a failed catch since continuing to throw after being hit
3937 * is too obviously silly.
3940 boomhit(obj, dx, dy)
3945 int boom; /* showsym[] index */
3947 boolean counterclockwise = TRUE; /* right-handed throw */
3949 /* counterclockwise traversal patterns:
3950 * ..........................54.................................
3951 * ..................43.....6..3....765.........................
3952 * ..........32.....5..2...7...2...8...4....87..................
3953 * .........4..1....6..1...8..1....9...3...9..6.....98..........
3954 * ..21@....5...@...7..@....9@......@12....@...5...@..7.....@9..
3955 * .3...9....6..9....89.....................1..4...1..6....1..8.
3956 * .4...8.....78.............................23....2..5...2...7.
3957 * ..567............................................34....3..6..
3958 * ........................................................45...
3959 * (invert rows for corresponding clockwise patterns)
3964 boom = counterclockwise ? S_boomleft : S_boomright;
3965 for (i = 0; i < 8; i++)
3966 if (xdir[i] == dx && ydir[i] == dy)
3968 tmp_at(DISP_FLASH, cmap_to_glyph(boom));
3969 for (ct = 0; ct < 10; ct++) {
3970 i = (i + 8) % 8; /* 0..7 (8 -> 0, -1 -> 7) */
3971 boom = (S_boomleft + S_boomright - boom); /* toggle */
3972 tmp_at(DISP_CHANGE, cmap_to_glyph(boom)); /* change glyph */
3977 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
3979 tmp_at(DISP_END, 0);
3982 if (!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ)
3983 || closed_door(bhitpos.x, bhitpos.y)) {
3988 if (bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
3989 if (Fumbling || rn2(20) >= ACURR(A_DEX)) {
3990 /* we hit ourselves */
3991 (void) thitu(10 + obj->spe, dmgval(obj, &youmonst), &obj,
3995 "
\83u
\81[
\83\81\83\89\83\93");
3998 } else { /* we catch it */
3999 tmp_at(DISP_END, 0);
4001 You("skillfully catch the boomerang.");
4003 You("
\8fã
\8eè
\82É
\83u
\81[
\83\81\83\89\83\93\82ð
\92Í
\82Ü
\82¦
\82½
\81D");
4007 tmp_at(bhitpos.x, bhitpos.y);
4009 if (IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) {
4014 pline("
\83J
\83\89\83\93\81I");
4015 break; /* boomerang falls on sink */
4017 /* ct==0, initial position, we want next delta to be same;
4018 ct==5, opposite position, repeat delta undoes first one */
4020 i += (counterclockwise ? -1 : 1);
4022 tmp_at(DISP_END, 0); /* do not leave last symbol */
4023 return (struct monst *) 0;
4026 /* used by buzz(); also used by munslime(muse.c); returns damage applied
4027 to mon; note: caller is responsible for killing mon if damage is fatal */
4029 zhitm(mon, type, nd, ootmp)
4030 register struct monst *mon;
4031 register int type, nd;
4032 struct obj **ootmp; /* to return worn armor for caller to disintegrate */
4034 register int tmp = 0;
4035 register int abstype = abs(type) % 10;
4036 boolean sho_shieldeff = FALSE;
4037 boolean spellcaster = is_hero_spell(type); /* maybe get a bonus! */
4039 *ootmp = (struct obj *) 0;
4041 case ZT_MAGIC_MISSILE:
4042 if (resists_magm(mon)) {
4043 sho_shieldeff = TRUE;
4048 tmp = spell_damage_bonus(tmp);
4051 if (resists_fire(mon)) {
4052 sho_shieldeff = TRUE;
4056 if (resists_cold(mon))
4059 tmp = spell_damage_bonus(tmp);
4060 if (burnarmor(mon)) {
4062 (void) destroy_mitem(mon, POTION_CLASS, AD_FIRE);
4064 (void) destroy_mitem(mon, SCROLL_CLASS, AD_FIRE);
4066 (void) destroy_mitem(mon, SPBOOK_CLASS, AD_FIRE);
4067 destroy_mitem(mon, FOOD_CLASS, AD_FIRE); /* carried slime */
4071 if (resists_cold(mon)) {
4072 sho_shieldeff = TRUE;
4076 if (resists_fire(mon))
4079 tmp = spell_damage_bonus(tmp);
4081 (void) destroy_mitem(mon, POTION_CLASS, AD_COLD);
4085 (void) sleep_monst(mon, d(nd, 25),
4086 type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0');
4088 case ZT_DEATH: /* death/disintegration */
4089 if (abs(type) != ZT_BREATH(ZT_DEATH)) { /* death */
4090 if (mon->data == &mons[PM_DEATH]) {
4091 mon->mhpmax += mon->mhpmax / 2;
4092 if (mon->mhpmax >= MAGIC_COOKIE)
4093 mon->mhpmax = MAGIC_COOKIE - 1;
4094 mon->mhp = mon->mhpmax;
4098 if (nonliving(mon->data) || is_demon(mon->data)
4099 || is_vampshifter(mon) || resists_magm(mon)) {
4100 /* similar to player */
4101 sho_shieldeff = TRUE;
4104 type = -1; /* so they don't get saving throws */
4108 if (resists_disint(mon)) {
4109 sho_shieldeff = TRUE;
4110 } else if (mon->misc_worn_check & W_ARMS) {
4111 /* destroy shield; victim survives */
4112 *ootmp = which_armor(mon, W_ARMS);
4113 } else if (mon->misc_worn_check & W_ARM) {
4114 /* destroy body armor, also cloak if present */
4115 *ootmp = which_armor(mon, W_ARM);
4116 if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
4117 m_useup(mon, otmp2);
4119 /* no body armor, victim dies; destroy cloak
4120 and shirt now in case target gets life-saved */
4122 if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
4123 m_useup(mon, otmp2);
4124 if ((otmp2 = which_armor(mon, W_ARMU)) != 0)
4125 m_useup(mon, otmp2);
4127 type = -1; /* no saving throw wanted */
4128 break; /* not ordinary damage */
4133 if (resists_elec(mon)) {
4134 sho_shieldeff = TRUE;
4136 /* can still blind the monster */
4140 tmp = spell_damage_bonus(tmp);
4141 if (!resists_blnd(mon)
4142 && !(type > 0 && u.uswallow && mon == u.ustuck)) {
4143 register unsigned rnd_tmp = rnd(50);
4145 if ((mon->mblinded + rnd_tmp) > 127)
4146 mon->mblinded = 127;
4148 mon->mblinded += rnd_tmp;
4151 (void) destroy_mitem(mon, WAND_CLASS, AD_ELEC);
4152 /* not actually possible yet */
4154 (void) destroy_mitem(mon, RING_CLASS, AD_ELEC);
4157 if (resists_poison(mon)) {
4158 sho_shieldeff = TRUE;
4164 if (resists_acid(mon)) {
4165 sho_shieldeff = TRUE;
4170 acid_damage(MON_WEP(mon));
4172 erode_armor(mon, ERODE_CORRODE);
4176 shieldeff(mon->mx, mon->my);
4177 if (is_hero_spell(type) && (Role_if(PM_KNIGHT) && u.uhave.questart))
4179 if (tmp > 0 && type >= 0
4180 && resist(mon, type < ZT_SPELL(0) ? WAND_CLASS : '\0', 0, NOTELL))
4183 tmp = 0; /* don't allow negative damage */
4184 debugpline3("zapped monster hp = %d (= %d - %d)", mon->mhp - tmp,
4191 zhitu(type, nd, fltxt, sx, sy)
4196 int dam = 0, abstyp = abs(type);
4200 Sprintf(buf, "%s
\82É
\82æ
\82Á
\82Ä", fltxt);
4204 switch (abstyp % 10) {
4205 case ZT_MAGIC_MISSILE:
4209 pline_The("missiles bounce off!");
4211 pline("
\96\82\96@
\82Ì
\96î
\82Í
\94½
\8eË
\82µ
\82½
\81I");
4214 exercise(A_STR, FALSE);
4218 if (Fire_resistance) {
4221 You("don't feel hot!");
4223 You("
\94M
\82³
\82ð
\8a´
\82¶
\82È
\82¢
\81I");
4224 ugolemeffects(AD_FIRE, d(nd, 6));
4229 if (burnarmor(&youmonst)) { /* "body hit" */
4231 destroy_item(POTION_CLASS, AD_FIRE);
4233 destroy_item(SCROLL_CLASS, AD_FIRE);
4235 destroy_item(SPBOOK_CLASS, AD_FIRE);
4236 destroy_item(FOOD_CLASS, AD_FIRE);
4240 if (Cold_resistance) {
4243 You("don't feel cold.");
4245 You("
\97â
\82½
\82³
\82ð
\8a´
\82¶
\82È
\82¢
\81D");
4246 ugolemeffects(AD_COLD, d(nd, 6));
4251 destroy_item(POTION_CLASS, AD_COLD);
4254 if (Sleep_resistance) {
4255 shieldeff(u.ux, u.uy);
4257 You("don't feel sleepy.");
4259 You("
\96°
\82
\82È
\82ç
\82È
\82¢
\81D");
4261 fall_asleep(-d(nd, 25), TRUE); /* sleep ray */
4265 if (abstyp == ZT_BREATH(ZT_DEATH)) {
4266 if (Disint_resistance) {
4268 You("are not disintegrated.");
4270 You("
\95ª
\89ð
\82³
\82ê
\82È
\82¢
\81D");
4273 /* destroy shield; other possessions are safe */
4274 (void) destroy_arm(uarms);
4277 /* destroy suit; if present, cloak goes too */
4279 (void) destroy_arm(uarmc);
4280 (void) destroy_arm(uarm);
4283 /* no shield or suit, you're dead; wipe out cloak
4284 and/or shirt in case of life-saving or bones */
4286 (void) destroy_arm(uarmc);
4288 (void) destroy_arm(uarmu);
4289 } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
4292 You("seem unaffected.");
4294 You("
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\82æ
\82¤
\82¾
\81D");
4296 } else if (Antimagic) {
4299 You("aren't affected.");
4301 You("
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\81D");
4304 killer.format = KILLED_BY_AN;
4305 Strcpy(killer.name, fltxt ? fltxt : "");
4306 /* when killed by disintegration breath, don't leave corpse */
4307 u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM;
4309 return; /* lifesaved */
4311 if (Shock_resistance) {
4314 You("aren't affected.");
4316 You("
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\81D");
4317 ugolemeffects(AD_ELEC, d(nd, 6));
4320 exercise(A_CON, FALSE);
4323 destroy_item(WAND_CLASS, AD_ELEC);
4325 destroy_item(RING_CLASS, AD_ELEC);
4329 poisoned("blast", A_DEX, "poisoned blast", 15, FALSE);
4331 poisoned("
\91§", A_DEX, "
\93Å
\82Ì
\91§", 15, FALSE);
4334 if (Acid_resistance) {
4336 pline_The("%s doesn't hurt.", hliquid("acid"));
4338 pline_The("%s
\82Å
\82Í
\8f\9d\82Â
\82©
\82È
\82©
\82Á
\82½
\81D", hliquid("
\8e_"));
4342 pline_The("%s burns!", hliquid("acid"));
4344 pline_The("%s
\82Å
\8fÄ
\82¯
\82½
\81I", hliquid("
\8e_"));
4346 exercise(A_STR, FALSE);
4348 /* using two weapons at once makes both of them more vulnerable */
4349 if (!rn2(u.twoweap ? 3 : 6))
4351 if (u.twoweap && !rn2(3))
4352 acid_damage(uswapwep);
4354 erode_armor(&youmonst, ERODE_CORRODE);
4358 /* Half_spell_damage protection yields half-damage for wands & spells,
4359 including hero's own ricochets; breath attacks do full damage */
4360 if (dam && Half_spell_damage && !(abstyp >= 20 && abstyp <= 29))
4361 dam = (dam + 1) / 2;
4362 losehp(dam, fltxt, KILLED_BY_AN);
4367 * burn objects (such as scrolls and spellbooks) on floor
4368 * at position x,y; return the number of objects burned
4371 burn_floor_objects(x, y, give_feedback, u_caused)
4373 boolean give_feedback; /* caller needs to decide about visibility checks */
4376 struct obj *obj, *obj2;
4377 long i, scrquan, delquan;
4378 char buf1[BUFSZ], buf2[BUFSZ];
4381 for (obj = level.objects[x][y]; obj; obj = obj2) {
4382 obj2 = obj->nexthere;
4383 if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS
4384 || (obj->oclass == FOOD_CLASS
4385 && obj->otyp == GLOB_OF_GREEN_SLIME)) {
4386 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL
4387 || obj_resists(obj, 2, 100))
4389 scrquan = obj->quan; /* number present */
4390 delquan = 0L; /* number to destroy */
4391 for (i = scrquan; i > 0L; i--)
4395 /* save name before potential delobj() */
4396 if (give_feedback) {
4398 Strcpy(buf1, (x == u.ux && y == u.uy)
4400 : distant_name(obj, xname));
4402 Strcpy(buf2, (x == u.ux && y == u.uy)
4404 : distant_name(obj, xname));
4405 obj->quan = scrquan;
4407 /* useupf(), which charges, only if hero caused damage */
4409 useupf(obj, delquan);
4410 else if (delquan < scrquan)
4411 obj->quan -= delquan;
4415 if (give_feedback) {
4418 pline("%ld %s burn.", delquan, buf2);
4420 pline("%ld%s
\82Ì%s
\82ª
\94R
\82¦
\82½
\81D",
4422 obj->oclass == SCROLL_CLASS ? "
\96\87" : "
\8dû",
4427 pline("%s burns.", An(buf1));
4429 pline("%s
\82Í
\94R
\82¦
\82½
\81D", buf1);
4437 /* will zap/spell/breath attack score a hit against armor class `ac'? */
4441 int type; /* either hero cast spell type or 0 */
4443 int chance = rn2(20);
4444 int spell_bonus = type ? spell_hit_bonus(type) : 0;
4446 /* small chance for naked target to avoid being hit */
4448 return rnd(10) < ac + spell_bonus;
4450 /* very high armor protection does not achieve invulnerability */
4453 return (3 - chance < ac + spell_bonus);
4457 disintegrate_mon(mon, type, fltxt)
4459 int type; /* hero vs other */
4462 struct obj *otmp, *otmp2, *m_amulet = mlifesaver(mon);
4464 if (canseemon(mon)) {
4467 pline("%s is disintegrated!", Monnam(mon));
4469 pline("%s
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81I", Monnam(mon));
4472 hit(fltxt, mon, "!");
4474 hit(fltxt, mon, "
\81I");
4477 /* note: worn amulet of life saving must be preserved in order to operate */
4478 #define oresist_disintegration(obj) \
4479 (objects[obj->otyp].oc_oprop == DISINT_RES || obj_resists(obj, 5, 50) \
4480 || is_quest_artifact(obj) || obj == m_amulet)
4482 for (otmp = mon->minvent; otmp; otmp = otmp2) {
4484 if (!oresist_disintegration(otmp)) {
4485 if (otmp->owornmask) {
4486 /* in case monster's life gets saved */
4487 mon->misc_worn_check &= ~otmp->owornmask;
4488 if (otmp->owornmask & W_WEP)
4489 setmnotwielded(mon, otmp);
4490 /* also dismounts hero if this object is steed's saddle */
4491 update_mon_intrinsics(mon, otmp, FALSE, TRUE);
4492 otmp->owornmask = 0L;
4494 obj_extract_self(otmp);
4495 obfree(otmp, (struct obj *) 0);
4499 #undef oresist_disintegration
4502 monkilled(mon, (char *) 0, -AD_RBRE);
4504 xkilled(mon, XKILL_NOMSG | XKILL_NOCORPSE);
4508 buzz(type, nd, sx, sy, dx, dy)
4513 dobuzz(type, nd, sx, sy, dx, dy, TRUE);
4517 * type == 0 to 9 : you shooting a wand
4518 * type == 10 to 19 : you casting a spell
4519 * type == 20 to 29 : you breathing as a monster
4520 * type == -10 to -19 : monster casting spell
4521 * type == -20 to -29 : monster breathing at you
4522 * type == -30 to -39 : monster shooting a wand
4523 * called with dx = dy = 0 with vertical bolts
4526 dobuzz(type, nd, sx, sy, dx, dy, say)
4527 register int type, nd;
4528 register xchar sx, sy;
4529 register int dx, dy;
4530 boolean say; /* Announce out of sight hit/miss events if true */
4532 int range, abstype = abs(type) % 10;
4533 register xchar lsx, lsy;
4536 boolean shopdamage = FALSE;
4541 /* if its a Hero Spell then get its SPE_TYPE */
4542 spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0;
4544 fltxt = flash_types[(type <= -30) ? abstype : abs(type)];
4550 tmp = zhitm(u.ustuck, type, nd, &otmp);
4555 pline("%s rips into %s%s", The(fltxt), mon_nam(u.ustuck),
4558 pline("%s
\82Í%s
\82ð
\82Ð
\82«
\82³
\82¢
\82½%s", fltxt, mon_nam(u.ustuck),
4561 /* Using disintegration from the inside only makes a hole... */
4562 if (tmp == MAGIC_COOKIE)
4564 if (DEADMONSTER(u.ustuck))
4571 if (dx == 0 && dy == 0)
4573 save_bhitpos = bhitpos;
4575 tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype));
4576 while (range-- > 0) {
4581 if (!isok(sx, sy) || levl[sx][sy].typ == STONE)
4585 if (cansee(sx, sy)) {
4586 /* reveal/unreveal invisible monsters before tmp_at() */
4587 if (mon && !canspotmon(mon))
4588 map_invisible(sx, sy);
4590 (void) unmap_invisible(sx, sy);
4591 if (ZAP_POS(levl[sx][sy].typ)
4592 || (isok(lsx, lsy) && cansee(lsx, lsy)))
4594 delay_output(); /* wait a little */
4597 /* hit() and miss() need bhitpos to match the target */
4598 bhitpos.x = sx, bhitpos.y = sy;
4599 /* Fireballs only damage when they explode */
4600 if (type != ZT_SPELL(ZT_FIRE)) {
4601 range += zap_over_floor(sx, sy, type, &shopdamage, 0);
4602 /* zap with fire -> melt ice -> drown monster, so monster
4603 found and cached above might not be here any more */
4608 if (type == ZT_SPELL(ZT_FIRE))
4611 mon->mstrategy &= ~STRAT_WAITMASK;
4613 notonhead = (mon->mx != bhitpos.x || mon->my != bhitpos.y);
4614 if (zap_hit(find_mac(mon), spell_type)) {
4615 if (mon_reflects(mon, (char *) 0)) {
4616 if (cansee(mon->mx, mon->my)) {
4617 hit(fltxt, mon, exclam(0));
4618 shieldeff(mon->mx, mon->my);
4620 (void) mon_reflects(mon,
4621 "But it reflects from %s %s!");
4623 (void) mon_reflects(mon,
4624 "
\82µ
\82©
\82µ
\82»
\82ê
\82Í%s
\82Ì%s
\82Å
\94½
\8eË
\82µ
\82½
\81I");
4630 boolean mon_could_move = mon->mcanmove;
4631 int tmp = zhitm(mon, type, nd, &otmp);
4633 if (is_rider(mon->data)
4634 && abs(type) == ZT_BREATH(ZT_DEATH)) {
4635 if (canseemon(mon)) {
4637 hit(fltxt, mon, ".");
4639 hit(fltxt, mon, "
\81D");
4641 pline("%s disintegrates.", Monnam(mon));
4643 pline("%s
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D", Monnam(mon));
4645 pline("%s body reintegrates before your %s!",
4646 s_suffix(Monnam(mon)),
4647 (eyecount(youmonst.data) == 1)
4649 : makeplural(body_part(EYE)));
4651 pline("%s
\82Ì
\91Ì
\82Í
\82 \82È
\82½
\82Ì
\96Ú
\82Ì
\91O
\82Å
\8dÄ
\8c\8b\8d\87\82µ
\82½
\81I",
4655 pline("%s resurrects!", Monnam(mon));
4657 pline("%s
\82Í
\91h
\82Á
\82½
\81I", Monnam(mon));
4659 mon->mhp = mon->mhpmax;
4660 break; /* Out of while loop */
4662 if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) {
4663 if (canseemon(mon)) {
4665 hit(fltxt, mon, ".");
4667 hit(fltxt, mon, "
\81D");
4669 pline("%s absorbs the deadly %s!", Monnam(mon),
4670 type == ZT_BREATH(ZT_DEATH) ? "blast"
4673 pline("%s
\82Í
\8e\80\82Ì%s
\82ð
\8bz
\8eû
\82µ
\82½
\81I", Monnam(mon),
4674 type == ZT_BREATH(ZT_DEATH) ? "
\91§"
4678 pline("It seems even stronger than before.");
4680 pline("
\82³
\82ç
\82É
\8b
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82³
\82¦
\82·
\82é
\81D");
4682 break; /* Out of while loop */
4685 if (tmp == MAGIC_COOKIE) { /* disintegration */
4686 disintegrate_mon(mon, type, fltxt);
4687 } else if (DEADMONSTER(mon)) {
4689 /* mon has just been killed by another monster */
4690 monkilled(mon, fltxt, AD_RBRE);
4692 int xkflags = XKILL_GIVEMSG; /* killed(mon); */
4694 /* killed by hero; we know 'type' isn't negative;
4695 if it's fire, highly flammable monsters leave
4696 no corpse; don't bother reporting that they
4697 "burn completely" -- unnecessary verbosity */
4698 if ((type % 10 == ZT_FIRE)
4699 /* paper golem or straw golem */
4700 && completelyburns(mon->data))
4701 xkflags |= XKILL_NOCORPSE;
4702 xkilled(mon, xkflags);
4706 /* normal non-fatal hit */
4707 if (say || canseemon(mon))
4708 hit(fltxt, mon, exclam(tmp));
4710 /* some armor was destroyed; no damage done */
4713 pline("%s %s is disintegrated!",
4714 s_suffix(Monnam(mon)),
4715 distant_name(otmp, xname));
4717 pline("%s
\82Ì%s
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81I",
4719 distant_name(otmp, xname));
4723 if (mon_could_move && !mon->mcanmove) /* ZT_SLEEP */
4729 if (say || canseemon(mon))
4732 } else if (sx == u.ux && sy == u.uy && range >= 0) {
4734 if (u.usteed && !rn2(3) && !mon_reflects(u.usteed, (char *) 0)) {
4737 } else if (zap_hit((int) u.uac, 0)) {
4740 pline("%s hits you!", The(fltxt));
4742 pline("%s
\82Í
\82 \82È
\82½
\82É
\96½
\92\86\82µ
\82½
\81I", fltxt);
4746 (void) ureflects("But %s reflects from your %s!",
4749 (void) ureflects("
\82µ
\82©
\82µ
\81C%s
\82Í
\82 \82È
\82½
\82Ì%s
\82É
\82æ
\82Á
\82Ä
\94½
\8eË
\82µ
\82½
\81D",
4754 pline("For some reason you are not affected.");
4756 pline("
\82È
\82º
\82©
\82 \82È
\82½
\82Í
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82©
\82Á
\82½
\81D");
4761 zhitu(type, nd, fltxt, sx, sy);
4763 } else if (!Blind) {
4765 pline("%s whizzes by you!", The(fltxt));
4767 pline("%s
\82Í
\82 \82È
\82½
\82Ì
\82»
\82Î
\82ð
\82©
\82·
\82ß
\82½
\81I", fltxt);
4768 } else if (abstype == ZT_LIGHTNING) {
4770 Your("%s tingles.", body_part(ARM));
4772 Your("%s
\82Í
\83q
\83\8a\83q
\83\8a\82µ
\82½
\81D", body_part(ARM));
4774 if (abstype == ZT_LIGHTNING)
4775 (void) flashburn((long) d(nd, 50));
4780 if (!ZAP_POS(levl[sx][sy].typ)
4781 || (closed_door(sx, sy) && range >= 0)) {
4782 int bounce, bchance;
4787 bchance = (levl[sx][sy].typ == STONE) ? 10
4788 : (In_mines(&u.uz) && IS_WALL(levl[sx][sy].typ)) ? 20
4791 fireball = (type == ZT_SPELL(ZT_FIRE));
4792 if ((--range > 0 && isok(lsx, lsy) && cansee(lsx, lsy))
4794 if (Is_airlevel(&u.uz)) { /* nothing to bounce off of */
4796 pline_The("%s vanishes into the aether!", fltxt);
4798 pline_The("%s
\82Í
\83G
\81[
\83e
\83\8b\8bó
\8aÔ
\82É
\8fÁ
\82¦
\82½
\81I", fltxt);
4800 type = ZT_WAND(ZT_FIRE); /* skip pending fireball */
4802 } else if (fireball) {
4805 break; /* fireballs explode before the obstacle */
4808 pline_The("%s bounces!", fltxt);
4810 pline_The("%s
\82Í
\94½
\8eË
\82µ
\82½
\81I", fltxt);
4812 if (!dx || !dy || !rn2(bchance)) {
4816 if (isok(sx, lsy) && ZAP_POS(rmn = levl[sx][lsy].typ)
4817 && !closed_door(sx, lsy)
4818 && (IS_ROOM(rmn) || (isok(sx + dx, lsy)
4819 && ZAP_POS(levl[sx + dx][lsy].typ))))
4821 if (isok(lsx, sy) && ZAP_POS(rmn = levl[lsx][sy].typ)
4822 && !closed_door(lsx, sy)
4823 && (IS_ROOM(rmn) || (isok(lsx, sy + dy)
4824 && ZAP_POS(levl[lsx][sy + dy].typ))))
4825 if (!bounce || rn2(2))
4839 tmp_at(DISP_CHANGE, zapdir_to_glyph(dx, dy, abstype));
4843 tmp_at(DISP_END, 0);
4844 if (type == ZT_SPELL(ZT_FIRE))
4845 explode(sx, sy, type, d(12, 6), 0, EXPL_FIERY);
4848 pay_for_damage(abstype == ZT_FIRE
4850 : abstype == ZT_COLD
4852 /* "damage" indicates wall rather than door */
4853 : abstype == ZT_ACID
4855 : abstype == ZT_DEATH
4860 pay_for_damage(abstype == ZT_FIRE
4862 : abstype == ZT_COLD
4863 ? "
\95²
\81X
\82É
\82·
\82é"
4864 : abstype == ZT_ACID
4865 ? "
\8f\9d\82Â
\82¯
\82é"
4866 : abstype == ZT_DEATH
4867 ? "
\95²
\8dÓ
\82·
\82é"
4868 : "
\94j
\89ó
\82·
\82é",
4871 bhitpos = save_bhitpos;
4879 struct rm *lev = &levl[x][y];
4885 msg = "The ice crackles and melts.";
4887 msg = "
\95X
\82Í
\83s
\83L
\83s
\83L
\96Â
\82è
\81C
\97n
\82¯
\82½
\81D";
4888 if (lev->typ == DRAWBRIDGE_UP || lev->typ == DRAWBRIDGE_DOWN) {
4889 lev->drawbridgemask &= ~DB_ICE; /* revert to DB_MOAT */
4890 } else { /* lev->typ == ICE */
4892 if (lev->icedpool == ICED_POOL)
4897 lev->typ = (lev->icedpool == ICED_POOL ? POOL : MOAT);
4901 spot_stop_timers(x, y, MELT_ICE_AWAY); /* no more ice to melt away */
4902 obj_ice_effects(x, y, FALSE);
4909 if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
4912 pline("%s settles...", An(xname(otmp)));
4914 pline("%s
\82Í
\82Í
\82Ü
\82Á
\82½
\81D
\81D
\81D", xname(otmp));
4916 obj_extract_self(otmp); /* boulder isn't being pushed */
4917 if (!boulder_hits_pool(otmp, x, y, FALSE))
4918 impossible("melt_ice: no pool?");
4919 /* try again if there's another boulder and pool didn't fill */
4920 } while (is_pool(x, y) && (otmp = sobj_at(BOULDER, x, y)) != 0);
4923 if (x == u.ux && y == u.uy)
4924 spoteffects(TRUE); /* possibly drown, notice objects */
4925 else if (is_pool(x, y) && (mtmp = m_at(x, y)) != 0)
4926 (void) minliquid(mtmp);
4929 #define MIN_ICE_TIME 50
4930 #define MAX_ICE_TIME 2000
4932 * Usually start a melt_ice timer; sometimes the ice will become
4933 * permanent instead.
4936 start_melt_ice_timeout(x, y, min_time)
4938 long min_time; /* <x,y>'s old melt timeout (deleted by time we get here) */
4943 when = (int) min_time;
4944 if (when < MIN_ICE_TIME - 1)
4945 when = MIN_ICE_TIME - 1;
4947 /* random timeout; surrounding ice locations ought to be a factor... */
4948 while (++when <= MAX_ICE_TIME)
4949 if (!rn2((MAX_ICE_TIME - when) + MIN_ICE_TIME))
4952 /* if we're within MAX_ICE_TIME, install a melt timer;
4953 otherwise, omit it to leave this ice permanent */
4954 if (when <= MAX_ICE_TIME) {
4955 where = ((long) x << 16) | (long) y;
4956 (void) start_timer((long) when, TIMER_LEVEL, MELT_ICE_AWAY,
4957 long_to_any(where));
4964 * Called when ice has melted completely away.
4967 melt_ice_away(arg, timeout)
4969 long timeout UNUSED;
4972 long where = arg->a_long;
4973 boolean save_mon_moving = context.mon_moving; /* will be False */
4975 /* melt_ice -> minliquid -> mondead|xkilled shouldn't credit/blame hero */
4976 context.mon_moving = TRUE; /* hero isn't causing this ice to melt */
4977 y = (xchar) (where & 0xFFFF);
4978 x = (xchar) ((where >> 16) & 0xFFFF);
4979 /* melt_ice does newsym when appropriate */
4981 melt_ice(x, y, "Some ice melts away.");
4983 melt_ice(x, y, "
\95X
\82ª
\8f
\82µ
\97n
\82¯
\82½
\81D");
4984 context.mon_moving = save_mon_moving;
4987 /* Burn floor scrolls, evaporate pools, etc... in a single square.
4988 * Used both for normal bolts of fire, cold, etc... and for fireballs.
4989 * Sets shopdamage to TRUE if a shop door is destroyed, and returns the
4990 * amount by which range is reduced (the latter is just ignored by fireballs)
4993 zap_over_floor(x, y, type, shopdamage, exploding_wand_typ)
4996 boolean *shopdamage;
4997 short exploding_wand_typ;
4999 const char *zapverb;
5002 struct rm *lev = &levl[x][y];
5003 boolean see_it = cansee(x, y), yourzap;
5004 int rangemod = 0, abstype = abs(type) % 10;
5009 if (t && t->ttyp == WEB) {
5010 /* a burning web is too flimsy to notice if you can't see it */
5013 Norep("A web bursts into flames!");
5015 Norep("
\82
\82à
\82Ì
\91\83\82Í
\89\8a\82É
\95ï
\82Ü
\82ê
\82½
\81I");
5016 (void) delfloortrap(t);
5021 melt_ice(x, y, (char *) 0);
5022 } else if (is_pool(x, y)) {
5024 const char *msgtxt = "You hear hissing gas.";
5026 const char *msgtxt = "
\82µ
\82ã
\81[
\82Á
\82Æ
\82¢
\82¤
\83K
\83X
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D";
5028 if (lev->typ != POOL) { /* MOAT or DRAWBRIDGE_UP */
5031 msgtxt = "Some water evaporates.";
5033 msgtxt = "
\82·
\82±
\82µ
\90\85\82ª
\8fö
\94
\82µ
\82½
\81D";
5036 lev->typ = ROOM, lev->flags = 0;
5037 t = maketrap(x, y, PIT);
5042 msgtxt = "The water evaporates.";
5044 msgtxt = "
\90\85\82ª
\8fö
\94
\82µ
\82½
\81D";
5046 Norep("%s", msgtxt);
5047 if (lev->typ == ROOM)
5049 } else if (IS_FOUNTAIN(lev->typ)) {
5052 pline("Steam billows from the fountain.");
5054 pline("
\90ò
\82©
\82ç
\8fö
\8bC
\82ª
\97§
\82¿
\82Ì
\82Ú
\82Á
\82½
\81D");
5056 dryup(x, y, type > 0);
5058 break; /* ZT_FIRE */
5061 if (is_pool(x, y) || is_lava(x, y)) {
5062 boolean lava = is_lava(x, y),
5063 moat = is_moat(x, y);
5065 if (lev->typ == WATER) {
5066 /* For now, don't let WATER freeze. */
5069 pline_The("%s freezes for a moment.", hliquid("water"));
5071 pline_The("%s
\82Í
\88ê
\8fu
\93\80\82Á
\82½
\81D", hliquid("
\90\85"));
5074 You_hear("a soft crackling.");
5076 You_hear("
\83s
\83L
\81I
\82Æ
\82¢
\82¤
\89¹
\82ð
\95·
\82¢
\82½
\81D");
5077 rangemod -= 1000; /* stop */
5081 Strcpy(buf, waterbody_name(x, y)); /* for MOAT */
5083 if (lev->typ == DRAWBRIDGE_UP) {
5084 lev->drawbridgemask &= ~DB_UNDER; /* clear lava */
5085 lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE);
5087 lev->icedpool = lava ? 0
5088 : (lev->typ == POOL) ? ICED_POOL
5090 lev->typ = lava ? ROOM : ICE;
5096 Norep("The %s cools and solidifies.", hliquid("lava"));
5098 Norep("%s
\82Í
\97â
\82¦
\8cÅ
\82Ü
\82Á
\82½
\81D", hliquid("lava"));
5101 Norep("The %s is bridged with ice!", buf);
5103 Norep("%s
\82É
\95X
\82Ì
\8b´
\82ª
\82©
\82¯
\82ç
\82ê
\82½
\81I", buf);
5106 Norep("The %s freezes.", hliquid("water"));
5108 Norep("%s
\82Í
\93\80\82Á
\82½
\81D", hliquid("
\95X"));
5112 You_hear("a crackling sound.");
5114 You_hear("
\83s
\83L
\83s
\83L
\83b
\82Æ
\82¢
\82¤
\89¹
\82ð
\95·
\82¢
\82½
\81D");
5116 if (x == u.ux && y == u.uy) {
5117 if (u.uinwater) { /* not just `if (Underwater)' */
5118 /* leave the no longer existent water */
5122 vision_full_recalc = 1;
5123 } else if (u.utrap && u.utraptype == TT_LAVA) {
5126 You("pass through the now-solid rock.");
5128 You("
\82¢
\82Ü
\8cÅ
\82
\82È
\82Á
\82½
\82Î
\82©
\82è
\82Ì
\90Î
\82Ì
\92\86\82ð
\82·
\82è
\94²
\82¯
\82½
\81D");
5131 set_utrap(rn1(50, 20), TT_INFLOOR);
5133 You("are firmly stuck in the cooling rock.");
5135 You("
\97â
\82¦
\82½
\8aâ
\82Ì
\82È
\82©
\82É
\82µ
\82Á
\82©
\82è
\82Æ
\96\84\82Ü
\82Á
\82½
\81D");
5138 } else if ((mon = m_at(x, y)) != 0) {
5139 /* probably ought to do some hefty damage to any
5140 non-ice creature caught in freezing water;
5141 at a minimum, eels are forced out of hiding */
5142 if (is_swimmer(mon->data) && mon->mundetected) {
5143 mon->mundetected = 0;
5148 start_melt_ice_timeout(x, y, 0L);
5149 obj_ice_effects(x, y, TRUE);
5153 } else if (is_ice(x, y)) {
5156 /* Already ice here, so just firm it up. */
5157 /* Now ensure that only ice that is already timed is affected */
5158 if ((melt_time = spot_time_left(x, y, MELT_ICE_AWAY)) != 0L) {
5159 spot_stop_timers(x, y, MELT_ICE_AWAY);
5160 start_melt_ice_timeout(x, y, melt_time);
5163 break; /* ZT_COLD */
5166 (void) create_gas_cloud(x, y, 1, 8);
5170 if (lev->typ == IRONBARS) {
5171 if ((lev->wall_info & W_NONDIGGABLE) != 0) {
5174 Norep("The %s corrode somewhat but remain intact.",
5176 Norep("%s
\82Í
\8f
\82µ
\92É
\82ñ
\82¾
\82ª
\82Ü
\82¾
\82µ
\82Á
\82©
\82è
\82µ
\82Ä
\82¢
\82é
\81D",
5177 defsyms[S_bars].explanation);
5178 /* but nothing actually happens... */
5183 Norep("The %s melt.", defsyms[S_bars].explanation);
5185 Norep("%s
\82ª
\97n
\82¯
\82½
\81D", defsyms[S_bars].explanation);
5186 if (*in_rooms(x, y, SHOPBASE)) {
5187 /* in case we ever have a shop bounded by bars */
5188 lev->typ = ROOM, lev->flags = 0;
5191 add_damage(x, y, (type >= 0) ? SHOP_BARS_COST : 0L);
5195 lev->typ = DOOR, lev->doormask = D_NODOOR;
5201 break; /* ZT_ACID */
5207 /* set up zap text for possible door feedback; for exploding wand, we
5208 want "the blast" rather than "your blast" even if hero caused it */
5209 yourzap = (type >= 0 && !exploding_wand_typ);
5211 zapverb = "blast"; /* breath attack or wand explosion */
5213 zapverb = "
\8fÕ
\8c\82"; /* breath attack or wand explosion */
5215 if (!exploding_wand_typ) {
5216 if (abs(type) < ZT_SPELL(0))
5218 zapverb = "bolt"; /* wand zap */
5220 zapverb = "
\8cõ
\90ü"; /* wand zap */
5222 else if (abs(type) < ZT_BREATH(0))
5226 zapverb = "
\8eô
\95¶";
5229 /* secret door gets revealed, converted into regular door */
5230 if (levl[x][y].typ == SDOOR) {
5231 cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */
5232 /* target spot will now pass closed_door() test below
5233 (except on rogue level) */
5237 pline("%s %s reveals a secret door.",
5238 yourzap ? "Your" : "The", zapverb);
5240 pline("%s
\82Å
\89B
\82µ
\94à
\82ª
\96¾
\82ç
\82©
\82É
\82È
\82Á
\82½
\81D", zapverb);
5242 else if (Is_rogue_level(&u.uz))
5243 draft_message(FALSE); /* "You feel a draft." (open doorway) */
5246 /* regular door absorbs remaining zap range, possibly gets destroyed */
5247 if (closed_door(x, y)) {
5248 int new_doormask = -1;
5249 const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0;
5254 new_doormask = D_NODOOR;
5256 see_txt = "The door is consumed in flames!";
5258 see_txt = "
\94à
\82Í
\89\8a\82Å
\8fÄ
\82«
\82Â
\82
\82³
\82ê
\82½
\81I";
5260 sense_txt = "smell smoke.";
5262 sense_txt = "
\89\8c\82Ì
\93õ
\82¢
\82ª
\82µ
\82½
\81D";
5265 new_doormask = D_NODOOR;
5267 see_txt = "The door freezes and shatters!";
5269 see_txt = "
\94à
\82Í
\93\80\82è
\81C
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81I";
5271 sense_txt = "feel cold.";
5273 sense_txt = "
\97â
\8bC
\82ð
\8a´
\82¶
\82½
\81D";
5276 /* death spells/wands don't disintegrate */
5277 if (abs(type) != ZT_BREATH(ZT_DEATH))
5279 new_doormask = D_NODOOR;
5281 see_txt = "The door disintegrates!";
5283 see_txt = "
\94à
\82Í
\95²
\8dÓ
\82³
\82ê
\82½
\81I";
5285 hear_txt = "crashing wood.";
5287 hear_txt = "
\96Ø
\82Ì
\89ó
\82ê
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D";
5290 new_doormask = D_BROKEN;
5292 see_txt = "The door splinters!";
5294 see_txt = "
\94à
\82Í
\82¸
\82½
\82¸
\82½
\82É
\82È
\82Á
\82½
\81I";
5296 hear_txt = "crackling.";
5298 hear_txt = "
\83s
\83L
\83s
\83L
\82Æ
\82¢
\82¤
\89¹
\82ð
\95·
\82¢
\82½
\81D";
5302 if (exploding_wand_typ > 0) {
5303 /* Magical explosion from misc exploding wand */
5304 if (exploding_wand_typ == WAN_STRIKING) {
5305 new_doormask = D_BROKEN;
5307 see_txt = "The door crashes open!";
5309 see_txt = "
\94à
\82Í
\89ó
\82ê
\82Ä
\8aJ
\82¢
\82½
\81I";
5311 sense_txt = "feel a burst of cool air.";
5313 sense_txt = "
\97â
\8bC
\82Ì
\8f[
\96\9e\82ð
\8a´
\82¶
\82½
\81D";
5318 /* "the door absorbs the blast" would be
5319 inaccurate for an exploding wand since
5320 other adjacent locations still get hit */
5321 if (exploding_wand_typ)
5323 pline_The("door remains intact.");
5325 pline_The("
\94à
\82Í
\96³
\8f\9d\82¾
\81D");
5328 pline_The("door absorbs %s %s!", yourzap ? "your" : "the",
5331 pline_The("
\94à
\82Í%s%s
\82ð
\8bz
\8eû
\82µ
\82½
\81I", yourzap ? "
\82 \82È
\82½
\82ª
\95ú
\82Á
\82½" : "",
5336 You_feel("vibrations.");
5338 You("
\90U
\93®
\82ð
\8a´
\82¶
\82½
\81D");
5341 if (new_doormask >= 0) { /* door gets broken */
5342 if (*in_rooms(x, y, SHOPBASE)) {
5344 add_damage(x, y, SHOP_DOOR_COST);
5346 } else /* caused by monster */
5347 add_damage(x, y, 0L);
5349 lev->doormask = new_doormask;
5350 unblock_point(x, y); /* vision */
5354 } else if (sense_txt) {
5355 #if 0 /*JP*//*
\81u
\82 \82È
\82½
\82Í
\81v
\82ª
\95s
\93K
\90Ø
\82È
\95¶
\82à
\82 \82é*/
5360 } else if (hear_txt)
5361 You_hear1(hear_txt);
5362 if (picking_at(x, y)) {
5369 if (OBJ_AT(x, y) && abstype == ZT_FIRE)
5370 if (burn_floor_objects(x, y, FALSE, type > 0) && couldsee(x, y)) {
5373 You("%s of smoke.", !Blind ? "see a puff" : "smell a whiff");
5375 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½");
5377 if ((mon = m_at(x, y)) != 0) {
5380 setmangry(mon, TRUE);
5381 if (mon->ispriest && *in_rooms(mon->mx, mon->my, TEMPLE))
5383 if (mon->isshk && !*u.ushops)
5390 /* fractured by pick-axe or wand of striking */
5393 register struct obj *obj; /* no texts here! */
5396 boolean by_you = !context.mon_moving;
5398 if (by_you && get_obj_location(obj, &x, &y, 0) && costly_spot(x, y)) {
5399 struct monst *shkp = 0;
5400 char objroom = *in_rooms(x, y, SHOPBASE);
5402 if (billable(&shkp, obj, objroom, FALSE)) {
5403 /* shop message says "you owe <shk> <$> for it!" so we need
5404 to precede that with a message explaining what "it" is */
5406 You("fracture %s %s.", s_suffix(shkname(shkp)), xname(obj));
5408 You("%s
\82Ì%s
\82ð
\89ó
\82µ
\82½
\81D", shkname(shkp), xname(obj));
5409 breakobj(obj, x, y, TRUE, FALSE); /* charges for shop goods */
5412 if (by_you && obj->otyp == BOULDER)
5416 obj->oclass = GEM_CLASS;
5417 obj->quan = (long) rn1(60, 7);
5418 obj->owt = weight(obj);
5419 obj->dknown = obj->bknown = obj->rknown = 0;
5420 obj->known = objects[obj->otyp].oc_uses_known ? 0 : 1;
5421 dealloc_oextra(obj);
5423 if (obj->where == OBJ_FLOOR) {
5424 obj_extract_self(obj); /* move rocks back on top */
5425 place_object(obj, obj->ox, obj->oy);
5426 if (!does_block(obj->ox, obj->oy, &levl[obj->ox][obj->oy]))
5427 unblock_point(obj->ox, obj->oy);
5428 if (cansee(obj->ox, obj->oy))
5429 newsym(obj->ox, obj->oy);
5433 /* handle statue hit by striking/force bolt/pick-axe */
5436 register struct obj *obj;
5438 /* [obj is assumed to be on floor, so no get_obj_location() needed] */
5439 struct trap *trap = t_at(obj->ox, obj->oy);
5441 boolean by_you = !context.mon_moving;
5443 if (trap && trap->ttyp == STATUE_TRAP
5444 && activate_statue_trap(trap, obj->ox, obj->oy, TRUE))
5446 /* drop any objects contained inside the statue */
5447 while ((item = obj->cobj) != 0) {
5448 obj_extract_self(item);
5449 place_object(item, obj->ox, obj->oy);
5451 if (by_you && Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC)) {
5453 You_feel("guilty about damaging such a historic statue.");
5455 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");
5464 * destroy_strings[dindx][0:singular,1:plural,2:killer_reason]
5465 * [0] freezing potion
5466 * [1] boiling potion other than oil
5467 * [2] boiling potion of oil
5468 * [3] burning scroll
5469 * [4] burning spellbook
5472 * (books, rings, and wands don't stack so don't need plural form;
5473 * crumbling ring doesn't do damage so doesn't need killer reason)
5475 const char *const destroy_strings[][3] = {
5476 /* also used in trap.c */
5478 { "freezes and shatters", "freeze and shatter", "shattered potion" },
5480 { "
\93\80\8c\8b\82µ
\82Ä
\8dÓ
\82¯
\82½", "
\93\80\8c\8b\82µ
\82Ä
\8dÓ
\82¯
\82½", "
\8dÓ
\82¯
\82½
\96ò
\95r
\82Å" },
5482 { "boils and explodes", "boil and explode", "boiling potion" },
5484 { "
\95¦
\93«
\82µ
\82Ä
\94\9a\94
\82µ
\82½", "
\95¦
\93«
\82µ
\82Ä
\94\9a\94
\82µ
\82½", "
\95¦
\93«
\82µ
\82½
\96ò
\82Å" },
5486 { "ignites and explodes", "ignite and explode", "exploding potion" },
5488 { "
\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Å" },
5490 { "catches fire and burns", "catch fire and burn", "burning scroll" },
5492 { "
\89Î
\82ª
\82Â
\82¢
\82Ä
\94R
\82¦
\82½", "
\89Î
\82ª
\82Â
\82¢
\82Ä
\94R
\82¦
\82½", "
\94R
\82¦
\82½
\8aª
\95¨
\82Å" },
5494 { "catches fire and burns", "", "burning book" },
5496 { "
\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Å" },
5498 { "turns to dust and vanishes", "", "" },
5500 { "
\90o
\82É
\82È
\82Á
\82Ä
\8fÁ
\82¦
\82½", "
\90o
\82É
\82È
\82Á
\82Ä
\8fÁ
\82¦
\82½", "" },
5502 { "breaks apart and explodes", "", "exploding wand" },
5504 { "
\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Å" },
5507 /* guts of destroy_item(), which ought to be called maybe_destroy_items();
5508 caller must decide whether obj is eligible */
5510 destroy_one_item(obj, osym, dmgtyp)
5515 int dmg, xresist, skip, dindx;
5517 boolean physical_damage;
5519 physical_damage = FALSE;
5521 /* lint suppression */
5527 if (osym == POTION_CLASS && obj->otyp != POT_OIL) {
5535 xresist = (Fire_resistance && obj->oclass != POTION_CLASS
5536 && obj->otyp != GLOB_OF_GREEN_SLIME);
5537 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
5539 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
5543 pline("%s glows a strange %s, but remains intact.",
5544 The(xname(obj)), hcolor("dark red"));
5546 pline("%s
\82Í
\8aï
\96
\82É%s
\8bP
\82¢
\82½
\82ª
\89½
\82à
\95Ï
\89»
\82µ
\82È
\82©
\82Á
\82½
\81D",
5547 xname(obj), jconj_adj(hcolor("
\88Ã
\8a\8c\90F
\82Ì")));
5553 dindx = (obj->otyp != POT_OIL) ? 1 : 2;
5565 if (obj->otyp == GLOB_OF_GREEN_SLIME) {
5566 dindx = 1; /* boil and explode */
5567 dmg = (obj->owt + 19) / 20;
5578 xresist = (Shock_resistance && obj->oclass != RING_CLASS);
5582 if (obj->otyp == RIN_SHOCK_RESISTANCE) {
5590 if (obj->otyp == WAN_LIGHTNING) {
5595 if (obj == current_wand) { skip++; break; }
5612 --quan; /* one will be used up elsewhere */
5613 for (i = cnt = 0L; i < quan; i++)
5621 ? ((quan == 1L) ? "Your" /* 1 of 1 */
5622 : "One of your") /* 1 of N */
5623 : ((cnt < quan) ? "Some of your" /* n of N */
5624 : (quan == 2L) ? "Both of your" /* 2 of 2 */
5625 : "All of your"); /* N of N */
5626 pline("%s %s %s!", mult, xname(obj),
5627 destroy_strings[dindx][(cnt > 1L)]);
5629 mult = (cnt == quan)
5631 : (cnt == 1L) ? "
\82Ì
\82Ð
\82Æ
\82Â" : "
\82Ì
\82¢
\82
\82Â
\82©";
5632 pline("
\82 \82È
\82½
\82Ì%s%s
\82Í%s
\81I", xname(obj), mult,
5633 destroy_strings[dindx][(cnt > 1L)]);
5635 if (osym == POTION_CLASS && dmgtyp != AD_COLD) {
5636 if (!breathless(youmonst.data) || haseyes(youmonst.data))
5639 if (obj->owornmask) {
5640 if (obj->owornmask & W_RING) /* ring being worn */
5645 if (obj == current_wand)
5646 current_wand = 0; /* destroyed */
5647 for (i = 0; i < cnt; i++)
5652 You("aren't hurt!");
5654 You("
\8f\9d\82Â
\82©
\82È
\82¢
\81I");
5656 const char *how = destroy_strings[dindx][2];
5657 boolean one = (cnt == 1L);
5659 if (dmgtyp == AD_FIRE && osym == FOOD_CLASS)
5661 how = "exploding glob of slime";
5663 how = "
\83X
\83\89\83C
\83\80\82Ì
\82Ë
\82Î
\82Ë
\82Î
\82Ì
\94\9a\94
\82Å";
5664 if (physical_damage)
5665 dmg = Maybe_Half_Phys(dmg);
5666 losehp(dmg, one ? how : (const char *) makeplural(how),
5667 one ? KILLED_BY_AN : KILLED_BY);
5668 exercise(A_STR, FALSE);
5674 /* target items of specified class for possible destruction */
5676 destroy_item(osym, dmgtyp)
5679 register struct obj *obj;
5680 int i, deferral_indx = 0;
5681 /* 1+52+1: try to handle a full inventory; it doesn't matter if
5682 inventory actually has more, even if everything should be deferred */
5683 unsigned short deferrals[1 + 52 + 1]; /* +1: gold, overflow */
5685 (void) memset((genericptr_t) deferrals, 0, sizeof deferrals);
5687 * Sometimes destroying an item can change inventory aside from
5688 * the item itself (cited case was a potion of unholy water; when
5689 * boiled, potionbreathe() caused hero to transform into were-beast
5690 * form and that resulted in dropping or destroying some worn armor).
5692 * Unlike other uses of the object bybass mechanism, destroy_item()
5693 * can be called multiple times for the same event. So we have to
5694 * explicitly clear it before each use and hope no other section of
5695 * code expects it to retain previous value.
5697 * Destruction of a ring of levitation or form change which pushes
5698 * off levitation boots could drop hero onto a fire trap that
5699 * could destroy other items and we'll get called recursively. Or
5700 * onto a trap which transports hero elsewhere, which won't disrupt
5701 * traversal but could yield message sequencing issues. So we
5702 * defer handling such things until after rest of inventory has
5703 * been processed. If some other combination of items and events
5704 * triggers a recursive call, rest of inventory after the triggering
5705 * item will be skipped by the outer call since the inner one will
5706 * have set the bypass bits of the whole list.
5708 * [Unfortunately, death while poly'd into flyer and subsequent
5709 * rehumanization could also drop hero onto a trap, and there's no
5710 * straightforward way to defer that. Things could be improved by
5711 * redoing this to use two passes, first to collect a list or array
5712 * of o_id and quantity of what is targetted for destruction,
5713 * second pass to handle the destruction.]
5715 bypass_objlist(invent, FALSE); /* clear bypass bit for invent */
5717 while ((obj = nxt_unbypassed_obj(invent)) != 0) {
5718 if (obj->oclass != osym)
5719 continue; /* test only objs of type osym */
5721 continue; /* don't destroy artifacts */
5722 if (obj->in_use && obj->quan == 1L)
5723 continue; /* not available */
5725 /* if loss of this item might dump us onto a trap, hold off
5726 until later because potential recursive destroy_item() will
5727 result in setting bypass bits on whole chain--we would skip
5728 the rest as already processed once control returns here */
5729 if (deferral_indx < SIZE(deferrals)
5730 && ((obj->owornmask != 0L
5731 && (objects[obj->otyp].oc_oprop == LEVITATION
5732 || objects[obj->otyp].oc_oprop == FLYING))
5733 /* destroyed wands and potions of polymorph don't trigger
5734 polymorph so don't need to be deferred */
5735 || (obj->otyp == POT_WATER && u.ulycn >= LOW_PM
5736 && (Upolyd ? obj->blessed : obj->cursed)))) {
5737 deferrals[deferral_indx++] = obj->o_id;
5740 /* obj is eligible; maybe destroy it */
5741 destroy_one_item(obj, osym, dmgtyp);
5743 /* if we saved some items for later (most likely just a worn ring
5744 of levitation) and they're still in inventory, handle them now */
5745 for (i = 0; i < deferral_indx; ++i) {
5746 /* note: obj->nobj is only referenced when obj is skipped;
5747 having obj be dropped or destroyed won't affect traversal */
5748 for (obj = invent; obj; obj = obj->nobj)
5749 if (obj->o_id == deferrals[i]) {
5750 destroy_one_item(obj, osym, dmgtyp);
5758 destroy_mitem(mtmp, osym, dmgtyp)
5768 if (mtmp == &youmonst) { /* this simplifies artifact_hit() */
5769 destroy_item(osym, dmgtyp);
5770 return 0; /* arbitrary; value doesn't matter to artifact_hit() */
5773 vis = canseemon(mtmp);
5775 /* see destroy_item(); object destruction could disrupt inventory list */
5776 bypass_objlist(mtmp->minvent, FALSE); /* clear bypass bit for minvent */
5778 while ((obj = nxt_unbypassed_obj(mtmp->minvent)) != 0) {
5779 if (obj->oclass != osym)
5780 continue; /* test only objs of type osym */
5787 if (osym == POTION_CLASS && obj->otyp != POT_OIL) {
5795 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
5797 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
5801 pline("%s glows a strange %s, but remains intact.",
5802 The(distant_name(obj, xname)), hcolor("dark red"));
5804 pline("%s
\82Í
\8aï
\96
\82É%s
\8bP
\82¢
\82½
\82ª
\89½
\82à
\95Ï
\89»
\82µ
\82È
\82©
\82Á
\82½
\81D",
5805 The(distant_name(obj, xname)), jconj_adj(hcolor("
\88Ã
\8a\8c\90F
\82Ì")));
5811 dindx = (obj->otyp != POT_OIL) ? 1 : 2;
5823 if (obj->otyp == GLOB_OF_GREEN_SLIME) {
5824 dindx = 1; /* boil and explode */
5825 tmp += (obj->owt + 19) / 20;
5839 if (obj->otyp == RIN_SHOCK_RESISTANCE) {
5846 if (obj->otyp == WAN_LIGHTNING) {
5863 for (i = cnt = 0L; i < quan; i++)
5872 (cnt == obj->quan) ? "" : (cnt > 1L) ? "Some of "
5874 (cnt == obj->quan) ? Yname2(obj) : yname(obj),
5875 destroy_strings[dindx][(cnt > 1L)]);
5877 pline("%s%s
\82Í%s
\81I",
5878 (cnt == obj->quan) ? Yname2(obj) : yname(obj),
5879 (cnt == obj->quan) ? "" : (cnt > 1L) ? "
\82Ì
\82¢
\82
\82Â
\82©"
5880 : "
\82Ì
\82Ð
\82Æ
\82Â",
5881 destroy_strings[dindx][(cnt > 1L)]);
5883 for (i = 0; i < cnt; i++)
5891 resist(mtmp, oclass, damage, tell)
5899 /* fake players always pass resistance test against Conflict
5900 (this doesn't guarantee that they're never affected by it) */
5901 if (oclass == RING_CLASS && !damage && !tell && is_mplayer(mtmp->data))
5911 break; /* instrument */
5914 break; /* artifact */
5929 dlev = (int) mtmp->m_lev;
5933 dlev = is_mplayer(mtmp->data) ? u.ulevel : 1;
5935 resisted = rn2(100 + alev - dlev) < mtmp->data->mr;
5938 shieldeff(mtmp->mx, mtmp->my);
5940 pline("%s resists!", Monnam(mtmp));
5942 pline("%s
\82Í
\96h
\82¢
\82¾
\81I", Monnam(mtmp));
5944 damage = (damage + 1) / 2;
5948 mtmp->mhp -= damage;
5949 if (DEADMONSTER(mtmp)) {
5951 monkilled(mtmp, "", AD_RBRE);
5959 #define MAXWISHTRY 5
5962 wishcmdassist(triesleft)
5965 static NEARDATA const char *
5969 "Enter the name of an object, such as \"potion of monster detection\",",
5970 "\"scroll labeled README\", \"elven mithril-coat\", or \"Grimtooth\"",
5971 "(without the quotes).",
5973 "For object types which come in stacks, you may specify a plural name",
5974 "such as \"potions of healing\", or specify a count, such as \"1000 gold",
5975 "pieces\", although that aspect of your wish might not be granted.",
5977 "You may also specify various prefix values which might be used to",
5978 "modify the item, such as \"uncursed\" or \"rustproof\" or \"+1\".",
5979 "Most modifiers shown when viewing your inventory can be specified.",
5981 "You may specify 'nothing' to explicitly decline this wish.",
5984 preserve_wishless[] = "Doing so will preserve 'wishless' conduct.",
5986 "If you specify an unrecognized object name %s%s time%s,",
5987 retry_too[] = "a randomly chosen item will be granted.",
5988 suppress_cmdassist[] =
5989 "(Suppress this assistance with !cmdassist in your config file.)",
5990 *cardinals[] = { "zero", "one", "two", "three", "four", "five" },
5991 too_many[] = "too many";
5996 win = create_nhwindow(NHW_TEXT);
5999 for (i = 0; i < SIZE(wishinfo) - 1; ++i)
6000 putstr(win, 0, wishinfo[i]);
6001 if (!u.uconduct.wishes)
6002 putstr(win, 0, preserve_wishless);
6004 Sprintf(buf, retry_info,
6005 (triesleft >= 0 && triesleft < SIZE(cardinals))
6006 ? cardinals[triesleft]
6008 (triesleft < MAXWISHTRY) ? " more" : "",
6010 putstr(win, 0, buf);
6011 putstr(win, 0, retry_too);
6013 if (iflags.cmdassist)
6014 putstr(win, 0, suppress_cmdassist);
6015 display_nhwindow(win, FALSE);
6016 destroy_nhwindow(win);
6022 char buf[BUFSZ] = DUMMY;
6023 char promptbuf[BUFSZ];
6024 struct obj *otmp, nothing;
6027 promptbuf[0] = '\0';
6028 nothing = zeroobj; /* lint suppression; only its address matters */
6031 You("may wish for an object.");
6033 You("
\96]
\82Ý
\82Ì
\82à
\82Ì
\82ð
\8eè
\82É
\93ü
\82ê
\82ç
\82ê
\82é
\81D");
6036 Strcpy(promptbuf, "For what do you wish");
6038 Strcpy(promptbuf, "(
\93ú
\96{
\8cê
\82Å)
\89½
\82ð
\82¨
\96]
\82Ý");
6039 if (iflags.cmdassist && tries > 0)
6041 Strcat(promptbuf, " (enter 'help' for assistance)");
6043 Strcat(promptbuf, " (
\8f\95\82¯
\82ª
\95K
\97v
\82È
\82ç 'help'
\82Æ
\93ü
\97Í)");
6045 Strcat(promptbuf, "?");
6047 Strcat(promptbuf, "
\81H");
6048 getlin(promptbuf, buf);
6049 (void) mungspaces(buf);
6050 if (buf[0] == '\033') {
6052 } else if (!strcmpi(buf, "help")) {
6053 wishcmdassist(MAXWISHTRY - tries);
6057 * Note: if they wished for and got a non-object successfully,
6058 * otmp == &zeroobj. That includes gold, or an artifact that
6059 * has been denied. Wishing for "nothing" requires a separate
6060 * value to remain distinct.
6062 otmp = readobjnam(buf, ¬hing);
6065 pline("Nothing fitting that description exists in the game.");
6067 pline("
\82¤
\81[
\82ñ
\81D
\82»
\82ñ
\82È
\82à
\82Ì
\82Í
\91¶
\8dÝ
\82µ
\82È
\82¢
\82æ
\82¤
\82¾
\81D");
6068 if (++tries < MAXWISHTRY)
6070 pline1(thats_enough_tries);
6071 otmp = readobjnam((char *) 0, (struct obj *) 0);
6073 return; /* for safety; should never happen */
6074 } else if (otmp == ¬hing) {
6075 /* explicitly wished for "nothing", presumably attempting
6076 to retain wishless conduct */
6081 u.uconduct.wishes++;
6083 if (otmp != &zeroobj) {
6086 *verb = ((Is_airlevel(&u.uz) || u.uinwater) ? "slip" : "drop"),
6088 *verb = ((Is_airlevel(&u.uz) || u.uinwater) ? "
\8a\8a\82è
\97\8e\82¿
\82½" : "
\97\8e\82¿
\82½"),
6090 *oops_msg = (u.uswallow
6091 ? "Oops! %s out of your reach!"
6092 : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
6093 || levl[u.ux][u.uy].typ < IRONBARS
6094 || levl[u.ux][u.uy].typ >= ICE)
6095 ? "Oops! %s away from you!"
6096 : "Oops! %s to the floor!");
6098 /* The(aobjnam()) is safe since otmp is unidentified -dlc */
6099 (void) hold_another_object(otmp, oops_msg,
6100 The(aobjnam(otmp, verb)),
6103 *oops_msg = (u.uswallow
6104 ? "
\82¨
\82Á
\82Æ
\81C%%s
\82ª
\93Í
\82©
\82È
\82¢
\82Æ
\82±
\82ë
\82É%s
\81I"
6105 : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
6106 || levl[u.ux][u.uy].typ < IRONBARS
6107 || levl[u.ux][u.uy].typ >= ICE)
6108 ? "
\82¨
\82Á
\82Æ
\81C%%s
\82ª
\8eè
\82©
\82ç%s
\81I"
6109 : "
\82¨
\82Á
\82Æ
\81C%%s
\82ª
\8f°
\82É%s
\81I");
6110 char oopsbuf[BUFSZ];
6111 Sprintf(oopsbuf, oops_msg, verb);
6113 (void) hold_another_object(otmp, oopsbuf,
6117 u.ublesscnt += rn1(100, 50); /* the gods take notice */