1 /* SCCS Id: @(#)zap.c 3.4 2003/08/24 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 #include "hack.h"
6
7 /* Disintegration rays have special treatment; corpses are never left.
8 * But the routine which calculates the damage is separate from the routine
9 * which kills the monster. The damage routine returns this cookie to
10 * indicate that the monster should be disintegrated.
11 */
12 #define MAGIC_COOKIE 1000
13
14 static NEARDATA boolean obj_zapped;
15 static NEARDATA int poly_zapped;
16
17 extern boolean notonhead; /* for long worms */
18
19 /* kludge to use mondied instead of killed */
20 extern boolean m_using;
21
22 STATIC_DCL void FDECL(costly_cancel, (struct obj *));
23 STATIC_DCL void FDECL(polyuse, (struct obj*, int, int));
24 STATIC_DCL void FDECL(create_polymon, (struct obj *, int));
25 STATIC_DCL boolean FDECL(zap_updown, (struct obj *));
26 STATIC_DCL int FDECL(zhitm, (struct monst *,int,int,struct obj **));
27 STATIC_DCL void FDECL(zhitu, (int,int,const char *,XCHAR_P,XCHAR_P));
28 STATIC_DCL void FDECL(revive_egg, (struct obj *));
29 #ifdef STEED
30 STATIC_DCL boolean FDECL(zap_steed, (struct obj *));
31 #endif
32
33 STATIC_DCL int FDECL(zap_hit, (int,int));
34 STATIC_DCL void FDECL(backfire, (struct obj *));
35 STATIC_DCL int FDECL(spell_hit_bonus, (int));
36
37 #define ZT_MAGIC_MISSILE (AD_MAGM-1)
38 #define ZT_FIRE (AD_FIRE-1)
39 #define ZT_COLD (AD_COLD-1)
40 #define ZT_SLEEP (AD_SLEE-1)
41 #define ZT_DEATH (AD_DISN-1) /* or disintegration */
42 #define ZT_LIGHTNING (AD_ELEC-1)
43 #define ZT_POISON_GAS (AD_DRST-1)
44 #define ZT_LAVA (AD_LAVA-1)
45 #define ZT_ACID (AD_ACID-1)
46 /* 9 is currently unassigned */
47
48 #define ZT_WAND(x) (x)
49 #define ZT_SPELL(x) (10+(x))
50 #define ZT_BREATH(x) (20+(x))
51
52 #define is_hero_spell(type) ((type) >= 10 && (type) < 20)
53
54 STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!";
55
56 const char * const flash_types[] = { /* also used in buzzmu(mcastu.c) */
57 "magic missile", /* Wands must be 0-9 */
58 "bolt of fire",
59 "bolt of cold",
60 "sleep ray",
61 "death ray",
62 "bolt of lightning",
63 "",
64 "",
65 "",
66 "",
67
68 "magic missile", /* Spell equivalents must be 10-19 */
69 "fireball",
70 "cone of cold",
71 "sleep ray",
72 "finger of death",
73 "bolt of lightning", /* There is no spell, used for retribution */
74 "",
75 "",
76 "",
77 "",
78
79 "blast of missiles", /* Dragon breath equivalents 20-29*/
80 "blast of fire",
81 "blast of frost",
82 "blast of sleep gas",
83 "blast of disintegration",
84 "blast of lightning",
85 "blast of poison gas",
86 "jet of molten lava",
87 "blast of acid",
88 ""
89 };
90
91 /* Routines for IMMEDIATE wands and spells. */
92 /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */
93 int
bhitm(mtmp,otmp)94 bhitm(mtmp, otmp)
95 struct monst *mtmp;
96 struct obj *otmp;
97 {
98 boolean wake = TRUE; /* Most 'zaps' should wake monster */
99 boolean reveal_invis = FALSE;
100 boolean visible = FALSE;
101 boolean knowninvisible = FALSE;
102 boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart;
103 int dmg, otyp = otmp->otyp;
104 const char *zap_type_text = "spell";
105 struct obj *obj;
106 boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC &&
107 mtmp->m_ap_type != M_AP_NOTHING);
108
109 if (u.uswallow && mtmp == u.ustuck)
110 reveal_invis = FALSE;
111
112 switch(otyp) {
113 case WAN_STRIKING:
114 zap_type_text = "wand";
115 /* fall through */
116 case SPE_FORCE_BOLT:
117 reveal_invis = TRUE;
118 if (resists_magm(mtmp)) { /* match effect on player */
119 shieldeff(mtmp->mx, mtmp->my);
120 break; /* skip makeknown */
121 } else if (u.uswallow || rnd(20) < 10 + find_mac(mtmp)) {
122 dmg = d(2,12);
123 if(dbldam) dmg *= 2;
124 if (otyp == SPE_FORCE_BOLT)
125 dmg += spell_damage_bonus();
126 hit(zap_type_text, mtmp, exclam(dmg));
127 (void) resist(mtmp, otmp->oclass, dmg, TELL);
128 } else miss(zap_type_text, mtmp);
129 makeknown(otyp);
130 break;
131 case WAN_SLOW_MONSTER:
132 case SPE_SLOW_MONSTER:
133 if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
134 mon_adjust_speed(mtmp, -1, otmp);
135 m_dowear(mtmp, FALSE); /* might want speed boots */
136 if (u.uswallow && (mtmp == u.ustuck) &&
137 is_whirly(mtmp->data)) {
138 You("disrupt %s!", mon_nam(mtmp));
139 pline("A huge hole opens up...");
140 expels(mtmp, mtmp->data, TRUE);
141 }
142 }
143 break;
144 case WAN_SPEED_MONSTER:
145 if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
146 mon_adjust_speed(mtmp, 1, otmp);
147 m_dowear(mtmp, FALSE); /* might want speed boots */
148 }
149 break;
150 case WAN_UNDEAD_TURNING:
151 case SPE_TURN_UNDEAD:
152 wake = FALSE;
153 if (unturn_dead(mtmp)) wake = TRUE;
154 if (is_undead(mtmp->data)) {
155 reveal_invis = TRUE;
156 wake = TRUE;
157 dmg = rnd(8);
158 if(dbldam) dmg *= 2;
159 if (otyp == SPE_TURN_UNDEAD)
160 dmg += spell_damage_bonus();
161 flags.bypasses = TRUE; /* for make_corpse() */
162 if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) {
163 if (mtmp->mhp > 0) monflee(mtmp, 0, FALSE, TRUE);
164 }
165 }
166 break;
167 case WAN_POLYMORPH:
168 case SPE_POLYMORPH:
169 case POT_POLYMORPH:
170 if (resists_magm(mtmp)) {
171 /* magic resistance protects from polymorph traps, so make
172 it guard against involuntary polymorph attacks too... */
173 shieldeff(mtmp->mx, mtmp->my);
174 } else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
175 /* natural shapechangers aren't affected by system shock
176 (unless protection from shapechangers is interfering
177 with their metabolism...) */
178 if (mtmp->cham == CHAM_ORDINARY && !rn2(25)) {
179 if (canseemon(mtmp)) {
180 pline("%s shudders!", Monnam(mtmp));
181 makeknown(otyp);
182 }
183 /* dropped inventory shouldn't be hit by this zap */
184 for (obj = mtmp->minvent; obj; obj = obj->nobj)
185 bypass_obj(obj);
186 /* flags.bypasses = TRUE; ## for make_corpse() */
187 /* no corpse after system shock */
188 xkilled(mtmp, 3);
189 } else if (newcham(mtmp, (struct permonst *)0,
190 (otyp != POT_POLYMORPH), FALSE)) {
191 if (!Hallucination && canspotmon(mtmp))
192 makeknown(otyp);
193 }
194 }
195 break;
196 case WAN_CANCELLATION:
197 case SPE_CANCELLATION:
198 (void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE);
199 break;
200 case WAN_TELEPORTATION:
201 case SPE_TELEPORT_AWAY:
202 visible = canspotmon(mtmp);
203 knowninvisible = knowninvisible(mtmp);
204 reveal_invis = !u_teleport_mon(mtmp, TRUE);
205 /* if the monster was teleported, the method of teleportation
206 was a wand, you could tell where the monster was before it
207 teleported, and you can tell that it has teleported and not
208 just turned invisible (or you have already identified wands
209 of make invisible), then automatically identify the wand */
210 if (!reveal_invis && otyp == WAN_TELEPORTATION && visible &&
211 (knowninvisible || canspotmon(mtmp) || objects[WAN_MAKE_INVISIBLE].oc_name_known))
212 makeknown(otyp);
213 break;
214 case WAN_MAKE_INVISIBLE:
215 {
216 int oldinvis = mtmp->minvis;
217 char nambuf[BUFSZ];
218
219 /* format monster's name before altering its visibility */
220 Strcpy(nambuf, Monnam(mtmp));
221 mon_set_minvis(mtmp);
222 /* if you've already identified wands of teleportation, automatically
223 identify wands of make invisible when they make a monster invisible */
224 if (!oldinvis && (knowninvisible(mtmp) || objects[WAN_TELEPORTATION].oc_name_known)) {
225 if (knowninvisible(mtmp)) pline("%s turns transparent!", nambuf);
226 makeknown(otyp);
227 }
228 break;
229 }
230 case WAN_NOTHING:
231 case WAN_LOCKING:
232 case SPE_WIZARD_LOCK:
233 wake = FALSE;
234 break;
235 case WAN_PROBING:
236 wake = FALSE;
237 reveal_invis = TRUE;
238 probe_monster(mtmp);
239 makeknown(otyp);
240 break;
241 case WAN_OPENING:
242 case SPE_KNOCK:
243 wake = FALSE; /* don't want immediate counterattack */
244 if (u.uswallow && mtmp == u.ustuck) {
245 if (is_animal(mtmp->data)) {
246 if (Blind) You_feel("a sudden rush of air!");
247 else pline("%s opens its mouth!", Monnam(mtmp));
248 }
249 expels(mtmp, mtmp->data, TRUE);
250 #ifdef STEED
251 } else if (!!(obj = which_armor(mtmp, W_SADDLE))) {
252 mtmp->misc_worn_check &= ~obj->owornmask;
253 update_mon_intrinsics(mtmp, obj, FALSE, FALSE);
254 obj->owornmask = 0L;
255 obj_extract_self(obj);
256 place_object(obj, mtmp->mx, mtmp->my);
257 /* call stackobj() if we ever drop anything that can merge */
258 newsym(mtmp->mx, mtmp->my);
259 #endif
260 }
261 break;
262 case SPE_HEALING:
263 case SPE_EXTRA_HEALING:
264 reveal_invis = TRUE;
265 if (mtmp->data != &mons[PM_PESTILENCE]) {
266 wake = FALSE; /* wakeup() makes the target angry */
267 mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4);
268 if (mtmp->mhp > mtmp->mhpmax)
269 mtmp->mhp = mtmp->mhpmax;
270 if (mtmp->mblinded) {
271 mtmp->mblinded = 0;
272 mtmp->mcansee = 1;
273 }
274 if (canseemon(mtmp)) {
275 if (disguised_mimic) {
276 if (mtmp->m_ap_type == M_AP_OBJECT &&
277 mtmp->mappearance == STRANGE_OBJECT) {
278 /* it can do better now */
279 set_mimic_sym(mtmp);
280 newsym(mtmp->mx, mtmp->my);
281 } else
282 mimic_hit_msg(mtmp, otyp);
283 } else pline("%s looks%s better.", Monnam(mtmp),
284 otyp == SPE_EXTRA_HEALING ? " much" : "" );
285 }
286 if (mtmp->mtame || mtmp->mpeaceful) {
287 adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type));
288 }
289 } else { /* Pestilence */
290 /* Pestilence will always resist; damage is half of 3d{4,8} */
291 (void) resist(mtmp, otmp->oclass,
292 d(3, otyp == SPE_EXTRA_HEALING ? 8 : 4), TELL);
293 }
294 break;
295 case WAN_LIGHT: /* (broken wand) */
296 if (flash_hits_mon(mtmp, otmp)) {
297 makeknown(WAN_LIGHT);
298 reveal_invis = TRUE;
299 }
300 break;
301 case WAN_SLEEP: /* (broken wand) */
302 /* [wakeup() doesn't rouse victims of temporary sleep,
303 so it's okay to leave `wake' set to TRUE here] */
304 reveal_invis = TRUE;
305 if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS))
306 slept_monst(mtmp);
307 if (!Blind) makeknown(WAN_SLEEP);
308 break;
309 case SPE_STONE_TO_FLESH:
310 if (monsndx(mtmp->data) == PM_STONE_GOLEM) {
311 char *name = Monnam(mtmp);
312 /* turn into flesh golem */
313 if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE, FALSE)) {
314 if (canseemon(mtmp))
315 pline("%s turns to flesh!", name);
316 } else {
317 if (canseemon(mtmp))
318 pline("%s looks rather fleshy for a moment.",
319 name);
320 }
321 } else
322 wake = FALSE;
323 break;
324 case SPE_DRAIN_LIFE:
325 dmg = rnd(8);
326 if(dbldam) dmg *= 2;
327 if (otyp == SPE_DRAIN_LIFE)
328 dmg += spell_damage_bonus();
329 if (resists_drli(mtmp))
330 shieldeff(mtmp->mx, mtmp->my);
331 else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) &&
332 mtmp->mhp > 0) {
333 mtmp->mhp -= dmg;
334 mtmp->mhpmax -= dmg;
335 if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1)
336 xkilled(mtmp, 1);
337 else {
338 mtmp->m_lev--;
339 if (canseemon(mtmp))
340 pline("%s suddenly seems weaker!", Monnam(mtmp));
341 }
342 }
343 break;
344 default:
345 warning("What an interesting effect (%d)", otyp);
346 break;
347 }
348 if(wake) {
349 if(mtmp->mhp > 0) {
350 wakeup(mtmp);
351 m_respond(mtmp);
352 if(mtmp->isshk && !*u.ushops) hot_pursuit(mtmp);
353 } else if(mtmp->m_ap_type)
354 seemimic(mtmp); /* might unblock if mimicing a boulder/door */
355 }
356 /* note: bhitpos won't be set if swallowed, but that's okay since
357 * reveal_invis will be false. We can't use mtmp->mx, my since it
358 * might be an invisible worm hit on the tail.
359 */
360 if (reveal_invis) {
361 /* workaround for Heisenberg's code */
362 if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) &&
363 !canspotmon(mtmp) && mtmp->data != &mons[PM_QUANTUM_MECHANIC])
364 map_invisible(bhitpos.x, bhitpos.y);
365 }
366 return 0;
367 }
368
369 void
probe_monster(mtmp)370 probe_monster(mtmp)
371 struct monst *mtmp;
372 {
373 struct obj *otmp;
374
375 /* identify type of dragon when probing */
376 if (monsndx(mtmp->data) >= PM_BABY_GRAY_DRAGON && monsndx(mtmp->data) <= PM_YELLOW_DRAGON ) {
377 if (monsndx(mtmp->data) < PM_GRAY_DRAGON) {
378 identify_dragon(monsndx(mtmp->data) - PM_BABY_GRAY_DRAGON);
379 } else {
380 identify_dragon(monsndx(mtmp->data) - PM_GRAY_DRAGON);
381 }
382 }
383
384 mstatusline(mtmp);
385 if (notonhead) return; /* don't show minvent for long worm tail */
386
387 #ifndef GOLDOBJ
388 if (mtmp->minvent || mtmp->mgold) {
389 #else
390 if (mtmp->minvent) {
391 #endif
392 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
393 otmp->dknown = 1; /* treat as "seen" */
394 (void) display_minventory(mtmp, MINV_ALL, (char *)0);
395 } else {
396 /* quantum mechanics don't stay in one place when probed */
397 pline("%s %s not carrying anything.", noit_Monnam(mtmp),
398 mtmp->data == &mons[PM_QUANTUM_MECHANIC] ? "was" : "is");
399 }
400 }
401
402 /*
403 * Return the object's physical location. This only makes sense for
404 * objects that are currently on the level (i.e. migrating objects
405 * are nowhere). By default, only things that can be seen (in hero's
406 * inventory, monster's inventory, or on the ground) are reported.
407 * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get
408 * the location of buried and contained objects. Note that if an
409 * object is carried by a monster, its reported position may change
410 * from turn to turn. This function returns FALSE if the position
411 * is not available or subject to the constraints above.
412 */
413 boolean
get_obj_location(obj,xp,yp,locflags)414 get_obj_location(obj, xp, yp, locflags)
415 struct obj *obj;
416 xchar *xp, *yp;
417 int locflags;
418 {
419 switch (obj->where) {
420 case OBJ_INVENT:
421 *xp = u.ux;
422 *yp = u.uy;
423 return TRUE;
424 case OBJ_FLOOR:
425 *xp = obj->ox;
426 *yp = obj->oy;
427 return TRUE;
428 case OBJ_MINVENT:
429 if (obj->ocarry->mx) {
430 *xp = obj->ocarry->mx;
431 *yp = obj->ocarry->my;
432 return TRUE;
433 }
434 break; /* !mx => migrating monster */
435 case OBJ_BURIED:
436 if (locflags & BURIED_TOO) {
437 *xp = obj->ox;
438 *yp = obj->oy;
439 return TRUE;
440 }
441 break;
442 case OBJ_CONTAINED:
443 if (locflags & CONTAINED_TOO)
444 return get_obj_location(obj->ocontainer, xp, yp, locflags);
445 break;
446 }
447 *xp = *yp = 0;
448 return FALSE;
449 }
450
451 boolean
get_mon_location(mon,xp,yp,locflags)452 get_mon_location(mon, xp, yp, locflags)
453 struct monst *mon;
454 xchar *xp, *yp;
455 int locflags; /* non-zero means get location even if monster is buried */
456 {
457 if (mon == &youmonst) {
458 *xp = u.ux;
459 *yp = u.uy;
460 return TRUE;
461 } else if (mon->mx > 0 && (!mon->mburied || locflags)) {
462 *xp = mon->mx;
463 *yp = mon->my;
464 return TRUE;
465 } else { /* migrating or buried */
466 *xp = *yp = 0;
467 return FALSE;
468 }
469 }
470
471 /* used by revive() and animate_statue() */
472 struct monst *
montraits(obj,cc)473 montraits(obj,cc)
474 struct obj *obj;
475 coord *cc;
476 {
477 struct monst *mtmp = (struct monst *)0;
478 struct monst *mtmp2 = (struct monst *)0;
479
480 if (obj->oxlth && (obj->oattached == OATTACHED_MONST))
481 mtmp2 = get_mtraits(obj, TRUE);
482 if (mtmp2) {
483 /* save_mtraits() validated mtmp2->mnum */
484 mtmp2->data = &mons[mtmp2->mnum];
485 if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data))
486 return (struct monst *)0;
487 mtmp = makemon(mtmp2->data,
488 cc->x, cc->y, NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
489 if (!mtmp) return mtmp;
490
491 /* heal the monster */
492 if (mtmp->mhpmax > mtmp2->mhpmax && is_rider(mtmp2->data))
493 mtmp2->mhpmax = mtmp->mhpmax;
494 mtmp2->mhp = mtmp2->mhpmax;
495 /* Get these ones from mtmp */
496 mtmp2->minvent = mtmp->minvent; /*redundant*/
497 /* monster ID is available if the monster died in the current
498 game, but should be zero if the corpse was in a bones level
499 (we cleared it when loading bones) */
500 if (!mtmp2->m_id)
501 mtmp2->m_id = mtmp->m_id;
502 mtmp2->mx = mtmp->mx;
503 mtmp2->my = mtmp->my;
504 mtmp2->mux = mtmp->mux;
505 mtmp2->muy = mtmp->muy;
506 mtmp2->mw = mtmp->mw;
507 mtmp2->wormno = mtmp->wormno;
508 mtmp2->misc_worn_check = mtmp->misc_worn_check;
509 mtmp2->weapon_check = mtmp->weapon_check;
510 mtmp2->mtrapseen = mtmp->mtrapseen;
511 mtmp2->mflee = mtmp->mflee;
512 mtmp2->mburied = mtmp->mburied;
513 mtmp2->mundetected = mtmp->mundetected;
514 mtmp2->mfleetim = mtmp->mfleetim;
515 mtmp2->mlstmv = mtmp->mlstmv;
516 mtmp2->m_ap_type = mtmp->m_ap_type;
517 /* set these ones explicitly */
518 mtmp2->mavenge = 0;
519 mtmp2->meating = 0;
520 mtmp2->mleashed = 0;
521 mtmp2->mtrapped = 0;
522 mtmp2->msleeping = 0;
523 mtmp2->mfrozen = 0;
524 mtmp2->mcanmove = 1;
525 /* most cancelled monsters return to normal,
526 but some need to stay cancelled */
527 if (!dmgtype(mtmp2->data, AD_SEDU)
528 #ifdef SEDUCE
529 && !dmgtype(mtmp2->data, AD_SSEX)
530 #endif
531 ) mtmp2->mcan = 0;
532 mtmp2->mcansee = 1; /* set like in makemon */
533 mtmp2->mblinded = 0;
534 mtmp2->mstun = 0;
535 mtmp2->mconf = 0;
536 replmon(mtmp,mtmp2);
537 }
538 return mtmp2;
539 }
540
541 /*
542 * get_container_location() returns the following information
543 * about the outermost container:
544 * loc argument gets set to:
545 * OBJ_INVENT if in hero's inventory; return 0.
546 * OBJ_FLOOR if on the floor; return 0.
547 * OBJ_BURIED if buried; return 0.
548 * OBJ_MINVENT if in monster's inventory; return monster.
549 * container_nesting is updated with the nesting depth of the containers
550 * if applicable.
551 */
552 struct monst *
get_container_location(obj,loc,container_nesting)553 get_container_location(obj, loc, container_nesting)
554 struct obj *obj;
555 int *loc;
556 int *container_nesting;
557 {
558 if (!obj || !loc)
559 return 0;
560
561 if (container_nesting) *container_nesting = 0;
562 while (obj && obj->where == OBJ_CONTAINED) {
563 if (container_nesting) *container_nesting += 1;
564 obj = obj->ocontainer;
565 }
566 if (obj) {
567 *loc = obj->where; /* outermost container's location */
568 if (obj->where == OBJ_MINVENT) return obj->ocarry;
569 }
570 return (struct monst *)0;
571 }
572
573 /*
574 * Attempt to revive the given corpse, return the revived monster if
575 * successful. Note: this does NOT use up the corpse if it fails.
576 */
577 struct monst *
revive(obj)578 revive(obj)
579 register struct obj *obj;
580 {
581 register struct monst *mtmp = (struct monst *)0;
582 struct obj *container = (struct obj *)0;
583 int container_nesting = 0;
584 schar savetame = 0;
585 boolean recorporealization = FALSE;
586 boolean in_container = FALSE;
587 if(obj->otyp == CORPSE) {
588 int montype = obj->corpsenm;
589 xchar x, y;
590
591 if (obj->where == OBJ_CONTAINED) {
592 /* deal with corpses in [possibly nested] containers */
593 struct monst *carrier;
594 int holder = 0;
595
596 container = obj->ocontainer;
597 carrier = get_container_location(container, &holder,
598 &container_nesting);
599 switch(holder) {
600 case OBJ_MINVENT:
601 x = carrier->mx; y = carrier->my;
602 in_container = TRUE;
603 break;
604 case OBJ_INVENT:
605 x = u.ux; y = u.uy;
606 in_container = TRUE;
607 break;
608 case OBJ_FLOOR:
609 if (!get_obj_location(obj, &x, &y, CONTAINED_TOO))
610 return (struct monst *) 0;
611 in_container = TRUE;
612 break;
613 default:
614 return (struct monst *)0;
615 }
616 } else {
617 /* only for invent, minvent, or floor */
618 if (!get_obj_location(obj, &x, &y, 0))
619 return (struct monst *) 0;
620 }
621 if (in_container) {
622 /* Rules for revival from containers:
623 - the container cannot be locked
624 - the container cannot be heavily nested (>2 is arbitrary)
625 - the container cannot be a statue or bag of holding
626 (except in very rare cases for the latter)
627 */
628 if (!x || !y || container->olocked || container_nesting > 2 ||
629 container->otyp == STATUE ||
630 (container->otyp == BAG_OF_HOLDING && rn2(40)))
631 return (struct monst *)0;
632 }
633
634 if (MON_AT(x,y)) {
635 coord new_xy;
636
637 if (enexto(&new_xy, x, y, &mons[montype]))
638 x = new_xy.x, y = new_xy.y;
639 }
640
641 if(cant_create(&montype, TRUE)) {
642 /* make a zombie or worm instead */
643 mtmp = makemon(&mons[montype], x, y,
644 NO_MINVENT|MM_NOWAIT);
645 if (mtmp) {
646 mtmp->mhp = mtmp->mhpmax = 100;
647 mon_adjust_speed(mtmp, 2, (struct obj *)0); /* MFAST */
648 }
649 } else {
650 if (obj->oxlth && (obj->oattached == OATTACHED_MONST)) {
651 coord xy;
652 xy.x = x; xy.y = y;
653 mtmp = montraits(obj, &xy);
654 if (mtmp && mtmp->mtame && !mtmp->isminion)
655 wary_dog(mtmp, TRUE);
656 } else
657 mtmp = makemon(&mons[montype], x, y,
658 NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
659 if (mtmp) {
660 if (obj->oxlth && (obj->oattached == OATTACHED_M_ID)) {
661 unsigned m_id;
662 struct monst *ghost;
663 (void) memcpy((genericptr_t)&m_id,
664 (genericptr_t)obj->oextra, sizeof(m_id));
665 ghost = find_mid(m_id, FM_FMON);
666 if (ghost && ghost->data == &mons[PM_GHOST]) {
667 int x2, y2;
668 x2 = ghost->mx; y2 = ghost->my;
669 if (ghost->mtame)
670 savetame = ghost->mtame;
671 if (canseemon(ghost))
672 pline("%s is suddenly drawn into its former body!",
673 Monnam(ghost));
674 mondead(ghost);
675 recorporealization = TRUE;
676 newsym(x2, y2);
677 }
678 /* don't mess with obj->oxlth here */
679 obj->oattached = OATTACHED_NOTHING;
680 }
681 /* Monster retains its name */
682 if (obj->onamelth)
683 mtmp = christen_monst(mtmp, ONAME(obj));
684 /* flag the quest leader as alive. */
685 if (mtmp->data->msound == MS_LEADER || mtmp->m_id ==
686 quest_status.leader_m_id)
687 quest_status.leader_is_dead = FALSE;
688 }
689 }
690 if (mtmp) {
691 if (obj->oeaten)
692 mtmp->mhp = eaten_stat(mtmp->mhp, obj);
693 /* track that this monster was revived at least once */
694 mtmp->mrevived = 1;
695
696 if (recorporealization) {
697 /* If mtmp is revivification of former tame ghost*/
698 if (savetame) {
699 struct monst *mtmp2 = tamedog(mtmp, (struct obj *)0);
700 if (mtmp2) {
701 mtmp2->mtame = savetame;
702 mtmp = mtmp2;
703 }
704 }
705 /* was ghost, now alive, it's all very confusing */
706 mtmp->mconf = 1;
707 }
708
709 switch (obj->where) {
710 case OBJ_INVENT:
711 useup(obj);
712 break;
713 case OBJ_FLOOR:
714 /* in case MON_AT+enexto for invisible mon */
715 x = obj->ox, y = obj->oy;
716 /* not useupf(), which charges */
717 if (obj->quan > 1L)
718 obj = splitobj(obj, 1L);
719 delobj(obj);
720 newsym(x, y);
721 break;
722 case OBJ_MINVENT:
723 m_useup(obj->ocarry, obj);
724 break;
725 case OBJ_CONTAINED:
726 obj_extract_self(obj);
727 obfree(obj, (struct obj *) 0);
728 break;
729 default:
730 panic("revive");
731 }
732 }
733 }
734 return mtmp;
735 }
736
737 STATIC_OVL void
revive_egg(obj)738 revive_egg(obj)
739 struct obj *obj;
740 {
741 /*
742 * Note: generic eggs with corpsenm set to NON_PM will never hatch.
743 */
744 if (obj->otyp != EGG) return;
745 if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE))
746 attach_egg_hatch_timeout(obj);
747 }
748
749 /* try to revive all corpses and eggs carried by `mon' */
750 int
unturn_dead(mon)751 unturn_dead(mon)
752 struct monst *mon;
753 {
754 struct obj *otmp, *otmp2;
755 struct monst *mtmp2;
756 char owner[BUFSZ], corpse[BUFSZ];
757 boolean youseeit;
758 int once = 0, res = 0;
759
760 youseeit = (mon == &youmonst) ? TRUE : canseemon(mon);
761 otmp2 = (mon == &youmonst) ? invent : mon->minvent;
762
763 while ((otmp = otmp2) != 0) {
764 otmp2 = otmp->nobj;
765 if (otmp->otyp == EGG)
766 revive_egg(otmp);
767 if (otmp->otyp != CORPSE) continue;
768 /* save the name; the object is liable to go away */
769 if (youseeit) Strcpy(corpse, corpse_xname(otmp, TRUE));
770
771 /* for a merged group, only one is revived; should this be fixed? */
772 if ((mtmp2 = revive(otmp)) != 0) {
773 ++res;
774 if (youseeit) {
775 if (!once++) Strcpy(owner,
776 (mon == &youmonst) ? "Your" :
777 s_suffix(Monnam(mon)));
778 pline("%s %s suddenly comes alive!", owner, corpse);
779 } else if (canseemon(mtmp2))
780 pline("%s suddenly appears!", Amonnam(mtmp2));
781 }
782 }
783 return res;
784 }
785
786 static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, 0 };
787
788 STATIC_OVL void
costly_cancel(obj)789 costly_cancel(obj)
790 register struct obj *obj;
791 {
792 char objroom;
793 struct monst *shkp = (struct monst *)0;
794
795 if (obj->no_charge) return;
796
797 switch (obj->where) {
798 case OBJ_INVENT:
799 if (obj->unpaid) {
800 shkp = shop_keeper(*u.ushops);
801 if (!shkp) return;
802 Norep("You cancel an unpaid object, you pay for it!");
803 bill_dummy_object(obj);
804 }
805 break;
806 case OBJ_FLOOR:
807 objroom = *in_rooms(obj->ox, obj->oy, SHOPBASE);
808 shkp = shop_keeper(objroom);
809 if (!shkp || !inhishop(shkp)) return;
810 if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) {
811 Norep("You cancel it, you pay for it!");
812 bill_dummy_object(obj);
813 } else
814 (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE);
815 break;
816 }
817 }
818
cancellable(obj)819 boolean cancellable(obj)
820 register struct obj *obj;
821 {
822 return objects[obj->otyp].oc_magic ||
823 (obj->spe &&
824 (obj->oclass == ARMOR_CLASS ||
825 obj->oclass == WEAPON_CLASS ||
826 is_weptool(obj))) ||
827 obj->otyp == POT_ACID ||
828 obj->otyp == POT_SICKNESS;
829 }
830
831 /* cancel obj, possibly carried by you or a monster */
832 void
cancel_item(obj)833 cancel_item(obj)
834 register struct obj *obj;
835 {
836 boolean u_ring = (obj == uleft) || (obj == uright);
837 register boolean holy = (obj->otyp == POT_WATER && obj->blessed);
838
839 switch(obj->otyp) {
840 case RIN_GAIN_STRENGTH:
841 if ((obj->owornmask & W_RING) && u_ring) {
842 ABON(A_STR) -= obj->spe;
843 flags.botl = 1;
844 }
845 break;
846 case RIN_GAIN_CONSTITUTION:
847 if ((obj->owornmask & W_RING) && u_ring) {
848 ABON(A_CON) -= obj->spe;
849 flags.botl = 1;
850 }
851 break;
852 case RIN_GAIN_INTELLIGENCE:
853 if ((obj->owornmask & W_RING) && u_ring) {
854 ABON(A_INT) -= obj->spe;
855 flags.botl = 1;
856 }
857 break;
858 case RIN_GAIN_WISDOM:
859 if ((obj->owornmask & W_RING) && u_ring) {
860 ABON(A_WIS) -= obj->spe;
861 flags.botl = 1;
862 }
863 break;
864 case RIN_GAIN_DEXTERITY:
865 if ((obj->owornmask & W_RING) && u_ring) {
866 ABON(A_DEX) -= obj->spe;
867 flags.botl = 1;
868 }
869 break;
870 case RIN_ADORNMENT:
871 if ((obj->owornmask & W_RING) && u_ring) {
872 ABON(A_CHA) -= obj->spe;
873 flags.botl = 1;
874 }
875 break;
876 case RIN_INCREASE_ACCURACY:
877 if ((obj->owornmask & W_RING) && u_ring)
878 u.uhitinc -= obj->spe;
879 break;
880 case RIN_INCREASE_DAMAGE:
881 if ((obj->owornmask & W_RING) && u_ring)
882 u.udaminc -= obj->spe;
883 break;
884 case GAUNTLETS_OF_DEXTERITY:
885 if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
886 ABON(A_DEX) -= obj->spe;
887 flags.botl = 1;
888 }
889 break;
890 case HELM_OF_BRILLIANCE:
891 if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
892 ABON(A_INT) -= obj->spe;
893 ABON(A_WIS) -= obj->spe;
894 flags.botl = 1;
895 }
896 break;
897 /* case RIN_PROTECTION: not needed */
898 }
899
900 /* MRKR: Cancelled *DSM reverts to scales. */
901 /* Suggested by Daniel Morris in RGRN */
902
903 if (obj->otyp >= GRAY_DRAGON_SCALE_MAIL &&
904 obj->otyp <= CHROMATIC_DRAGON_SCALE_MAIL) {
905 /* dragon scale mail reverts to dragon scales */
906
907 boolean worn = (obj == uarm);
908
909 if (!Blind) {
910 char buf[BUFSZ];
911 pline("%s %s reverts to its natural form!",
912 Shk_Your(buf, obj), xname(obj));
913 } else if (worn) {
914 Your("armor feels looser.");
915 }
916 costly_cancel(obj);
917
918 if (worn) {
919 setworn((struct obj *)0, W_ARM);
920 }
921
922 /* assumes same order */
923 obj->otyp = GRAY_DRAGON_SCALES +
924 obj->otyp - GRAY_DRAGON_SCALE_MAIL;
925
926 if (worn) {
927 setworn(obj, W_ARM);
928 }
929 }
930
931 if (objects[obj->otyp].oc_magic
932 || (obj->spe && (obj->oclass == ARMOR_CLASS ||
933 obj->oclass == WEAPON_CLASS || is_weptool(obj)))
934 || obj->otyp == POT_ACID || obj->otyp == POT_SICKNESS) {
935 if (obj->spe != ((obj->oclass == WAND_CLASS) ? -1 : 0) &&
936 obj->otyp != WAN_CANCELLATION &&
937 /* can't cancel cancellation */
938 obj->otyp != MAGIC_LAMP &&
939 obj->otyp != CANDELABRUM_OF_INVOCATION) {
940 costly_cancel(obj);
941 obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0;
942 }
943 switch (obj->oclass) {
944 case SCROLL_CLASS:
945 costly_cancel(obj);
946 obj->otyp = SCR_BLANK_PAPER;
947 obj->spe = 0;
948 break;
949 case SPBOOK_CLASS:
950 if (obj->otyp != SPE_CANCELLATION &&
951 obj->otyp != SPE_BOOK_OF_THE_DEAD) {
952 costly_cancel(obj);
953 obj->otyp = SPE_BLANK_PAPER;
954 }
955 break;
956 case POTION_CLASS:
957 costly_cancel(obj);
958 if (obj->otyp == POT_SICKNESS ||
959 obj->otyp == POT_SEE_INVISIBLE) {
960 /* sickness is "biologically contaminated" fruit juice; cancel it
961 * and it just becomes fruit juice... whereas see invisible
962 * tastes like "enchanted" fruit juice, it similarly cancels.
963 */
964 obj->otyp = POT_FRUIT_JUICE;
965 } else if (obj->otyp == POT_VAMPIRE_BLOOD) {
966 obj->otyp = POT_BLOOD;
967 } else {
968 obj->otyp = POT_WATER;
969 obj->odiluted = 0; /* same as any other water */
970 }
971 break;
972 }
973 }
974 if (holy) costly_cancel(obj);
975 unbless(obj);
976 uncurse(obj);
977 #ifdef INVISIBLE_OBJECTS
978 if (obj->oinvis) obj->oinvis = 0;
979 #endif
980 return;
981 }
982
983
984 /* Remove a positive enchantment or charge from obj,
985 * possibly carried by you or a monster
986 */
987 boolean
drain_item(obj)988 drain_item(obj)
989 register struct obj *obj;
990 {
991 boolean u_ring;
992
993 /* Is this a charged/enchanted object? */
994 if (!obj || (!objects[obj->otyp].oc_charged &&
995 obj->oclass != WEAPON_CLASS &&
996 obj->oclass != ARMOR_CLASS && !is_weptool(obj)) ||
997 obj->spe <= 0)
998 return (FALSE);
999 if (obj_resists(obj, 10, 90))
1000 return (FALSE);
1001
1002 /* Charge for the cost of the object */
1003 costly_cancel(obj); /* The term "cancel" is okay for now */
1004
1005 /* Drain the object and any implied effects */
1006 obj->spe--;
1007 u_ring = (obj == uleft) || (obj == uright);
1008 switch(obj->otyp) {
1009 case RIN_GAIN_STRENGTH:
1010 if ((obj->owornmask & W_RING) && u_ring) {
1011 ABON(A_STR)--;
1012 flags.botl = 1;
1013 }
1014 break;
1015 case RIN_GAIN_CONSTITUTION:
1016 if ((obj->owornmask & W_RING) && u_ring) {
1017 ABON(A_CON)--;
1018 flags.botl = 1;
1019 }
1020 break;
1021 case RIN_ADORNMENT:
1022 if ((obj->owornmask & W_RING) && u_ring) {
1023 ABON(A_CHA)--;
1024 flags.botl = 1;
1025 }
1026 break;
1027 case RIN_INCREASE_ACCURACY:
1028 if ((obj->owornmask & W_RING) && u_ring)
1029 u.uhitinc--;
1030 break;
1031 case RIN_INCREASE_DAMAGE:
1032 if ((obj->owornmask & W_RING) && u_ring)
1033 u.udaminc--;
1034 break;
1035 case HELM_OF_BRILLIANCE:
1036 if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
1037 ABON(A_INT)--;
1038 ABON(A_WIS)--;
1039 flags.botl = 1;
1040 }
1041 break;
1042 case GAUNTLETS_OF_DEXTERITY:
1043 if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
1044 ABON(A_DEX)--;
1045 flags.botl = 1;
1046 }
1047 break;
1048 case RIN_PROTECTION:
1049 flags.botl = 1;
1050 break;
1051 }
1052 if (carried(obj)) update_inventory();
1053 return (TRUE);
1054 }
1055
1056 boolean
obj_resists(obj,ochance,achance)1057 obj_resists(obj, ochance, achance)
1058 struct obj *obj;
1059 int ochance, achance; /* percent chance for ordinary objects, artifacts */
1060 {
1061 if (obj->otyp == AMULET_OF_YENDOR ||
1062 obj->otyp == SPE_BOOK_OF_THE_DEAD ||
1063 obj->otyp == CANDELABRUM_OF_INVOCATION ||
1064 obj->otyp == BELL_OF_OPENING ||
1065 (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm]))) {
1066 return TRUE;
1067 } else {
1068 int chance = rn2(100);
1069
1070 return((boolean)(chance < (obj->oartifact ? achance : ochance)));
1071 }
1072 }
1073
1074 boolean
obj_shudders(obj)1075 obj_shudders(obj)
1076 struct obj *obj;
1077 {
1078 int zap_odds;
1079
1080 if (obj->oclass == WAND_CLASS)
1081 zap_odds = 3; /* half-life = 2 zaps */
1082 else if (obj->cursed)
1083 zap_odds = 3; /* half-life = 2 zaps */
1084 else if (obj->blessed)
1085 zap_odds = 12; /* half-life = 8 zaps */
1086 else
1087 zap_odds = 8; /* half-life = 6 zaps */
1088
1089 /* adjust for "large" quantities of identical things */
1090 if(obj->quan > 4L) zap_odds /= 2;
1091
1092 return((boolean)(! rn2(zap_odds)));
1093 }
1094
1095 /* Use up at least minwt number of things made of material mat.
1096 * There's also a chance that other stuff will be used up. Finally,
1097 * there's a random factor here to keep from always using the stuff
1098 * at the top of the pile.
1099 */
1100 STATIC_OVL void
polyuse(objhdr,mat,minwt)1101 polyuse(objhdr, mat, minwt)
1102 struct obj *objhdr;
1103 int mat, minwt;
1104 {
1105 register struct obj *otmp, *otmp2;
1106
1107 for(otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) {
1108 otmp2 = otmp->nexthere;
1109 if (otmp == uball || otmp == uchain) continue;
1110 if (obj_resists(otmp, 0, 0)) continue; /* preserve unique objects */
1111 #ifdef MAIL
1112 if (otmp->otyp == SCR_MAIL) continue;
1113 #endif
1114
1115 if (((int) objects[otmp->otyp].oc_material == mat) ==
1116 (rn2(minwt + 1) != 0)) {
1117 /* appropriately add damage to bill */
1118 if (costly_spot(otmp->ox, otmp->oy)) {
1119 if (*u.ushops)
1120 addtobill(otmp, FALSE, FALSE, FALSE);
1121 else
1122 (void)stolen_value(otmp,
1123 otmp->ox, otmp->oy, FALSE, FALSE);
1124 }
1125 if (otmp->quan < LARGEST_INT)
1126 minwt -= (int)otmp->quan;
1127 else
1128 minwt = 0;
1129 delobj(otmp);
1130 }
1131 }
1132 }
1133
1134 /*
1135 * Polymorph some of the stuff in this pile into a monster, preferably
1136 * a golem of the kind okind.
1137 */
1138 STATIC_OVL void
create_polymon(obj,okind)1139 create_polymon(obj, okind)
1140 struct obj *obj;
1141 int okind;
1142 {
1143 struct permonst *mdat = (struct permonst *)0;
1144 struct monst *mtmp;
1145 const char *material;
1146 int pm_index;
1147
1148 /* no golems if you zap only one object -- not enough stuff */
1149 if(!obj || (!obj->nexthere && obj->quan == 1L)) return;
1150
1151 /* some of these choices are arbitrary */
1152 switch(okind) {
1153 case IRON:
1154 case METAL:
1155 case MITHRIL:
1156 pm_index = PM_IRON_GOLEM;
1157 material = "metal ";
1158 break;
1159 case COPPER:
1160 case SILVER:
1161 case PLATINUM:
1162 case GEMSTONE:
1163 case MINERAL:
1164 pm_index = rn2(2) ? PM_STONE_GOLEM : PM_CLAY_GOLEM;
1165 material = "lithic ";
1166 break;
1167 case 0:
1168 case FLESH:
1169 /* there is no flesh type, but all food is type 0, so we use it */
1170 pm_index = PM_FLESH_GOLEM;
1171 material = "organic ";
1172 break;
1173 case WAX:
1174 pm_index = PM_WAX_GOLEM;
1175 material = "wax ";
1176 break;
1177 case WOOD:
1178 pm_index = PM_WOOD_GOLEM;
1179 material = "wood ";
1180 break;
1181 case LEATHER:
1182 pm_index = PM_LEATHER_GOLEM;
1183 material = "leather ";
1184 break;
1185 case CLOTH:
1186 pm_index = PM_ROPE_GOLEM;
1187 material = "cloth ";
1188 break;
1189 case BONE:
1190 pm_index = PM_SKELETON; /* nearest thing to "bone golem" */
1191 material = "bony ";
1192 break;
1193 case GOLD:
1194 pm_index = PM_GOLD_GOLEM;
1195 material = "gold ";
1196 break;
1197 case GLASS:
1198 pm_index = PM_GLASS_GOLEM;
1199 material = "glassy ";
1200 break;
1201 case PAPER:
1202 pm_index = PM_PAPER_GOLEM;
1203 material = "paper ";
1204 break;
1205 default:
1206 /* if all else fails... */
1207 pm_index = PM_STRAW_GOLEM;
1208 material = "";
1209 break;
1210 }
1211
1212 if (!(mvitals[pm_index].mvflags & G_GENOD))
1213 mdat = &mons[pm_index];
1214
1215 mtmp = makemon(mdat, obj->ox, obj->oy, NO_MM_FLAGS);
1216 polyuse(obj, okind, (int)mons[pm_index].cwt);
1217
1218 if(mtmp && cansee(mtmp->mx, mtmp->my)) {
1219 pline("Some %sobjects meld, and %s arises from the pile!",
1220 material, a_monnam(mtmp));
1221 }
1222 }
1223
1224 /* Assumes obj is on the floor. */
1225 void
do_osshock(obj)1226 do_osshock(obj)
1227 struct obj *obj;
1228 {
1229 long i;
1230
1231 #ifdef MAIL
1232 if (obj->otyp == SCR_MAIL) return;
1233 #endif
1234 obj_zapped = TRUE;
1235
1236 if(poly_zapped < 0) {
1237 /* some may metamorphosize */
1238 for (i = obj->quan; i; i--)
1239 if (! rn2(Luck + 45)) {
1240 poly_zapped = objects[obj->otyp].oc_material;
1241 break;
1242 }
1243 }
1244
1245 /* if quan > 1 then some will survive intact */
1246 if (obj->quan > 1L) {
1247 if (obj->quan > LARGEST_INT)
1248 obj = splitobj(obj, (long)rnd(30000));
1249 else
1250 obj = splitobj(obj, (long)rnd((int)obj->quan - 1));
1251 }
1252
1253 /* appropriately add damage to bill */
1254 if (costly_spot(obj->ox, obj->oy)) {
1255 if (*u.ushops)
1256 addtobill(obj, FALSE, FALSE, FALSE);
1257 else
1258 (void)stolen_value(obj,
1259 obj->ox, obj->oy, FALSE, FALSE);
1260 }
1261
1262 /* zap the object */
1263 delobj(obj);
1264 }
1265
1266 /*
1267 * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT
1268 * then pick random object from the source's class (this is the standard
1269 * "polymorph" case). If ID is set to a specific object, inhibit fusing
1270 * n objects into 1. This could have been added as a flag, but currently
1271 * it is tied to not being the standard polymorph case. The new polymorphed
1272 * object replaces obj in its link chains. Return value is a pointer to
1273 * the new object.
1274 *
1275 * This should be safe to call for an object anywhere.
1276 */
1277 struct obj *
poly_obj(obj,id)1278 poly_obj(obj, id)
1279 struct obj *obj;
1280 int id;
1281 {
1282 struct obj *otmp;
1283 xchar ox, oy;
1284 boolean can_merge = (id == STRANGE_OBJECT);
1285 int obj_location = obj->where;
1286
1287 if (obj->otyp == BOULDER && In_sokoban(&u.uz))
1288 sokoban_trickster(); /* Sokoban guilt */
1289 if (id == STRANGE_OBJECT) { /* preserve symbol */
1290 int try_limit = 3;
1291 /* Try up to 3 times to make the magic-or-not status of
1292 the new item be the same as it was for the old one. */
1293 otmp = (struct obj *)0;
1294 do {
1295 if (otmp) delobj(otmp);
1296 otmp = mkobj(obj->oclass, FALSE);
1297 } while (--try_limit > 0 &&
1298 objects[obj->otyp].oc_magic != objects[otmp->otyp].oc_magic);
1299 } else {
1300 /* literally replace obj with this new thing */
1301 otmp = mksobj(id, FALSE, FALSE);
1302 /* Actually more things use corpsenm but they polymorph differently */
1303 #define USES_CORPSENM(typ) ((typ)==CORPSE || (typ)==STATUE || (typ)==FIGURINE)
1304 if (USES_CORPSENM(obj->otyp) && USES_CORPSENM(id))
1305 otmp->corpsenm = obj->corpsenm;
1306 #undef USES_CORPSENM
1307 }
1308
1309 /* preserve quantity */
1310 otmp->quan = obj->quan;
1311 /* preserve the shopkeepers (lack of) interest */
1312 otmp->no_charge = obj->no_charge;
1313 /* preserve inventory letter if in inventory */
1314 if (obj_location == OBJ_INVENT)
1315 otmp->invlet = obj->invlet;
1316 #ifdef MAIL
1317 /* You can't send yourself 100 mail messages and then
1318 * polymorph them into useful scrolls
1319 */
1320 if (obj->otyp == SCR_MAIL) {
1321 otmp->otyp = SCR_MAIL;
1322 otmp->spe = 1;
1323 }
1324 #endif
1325
1326 /* avoid abusing eggs laid by you */
1327 if (obj->otyp == EGG && obj->spe) {
1328 int mnum, tryct = 100;
1329
1330 /* first, turn into a generic egg */
1331 if (otmp->otyp == EGG)
1332 kill_egg(otmp);
1333 else {
1334 otmp->otyp = EGG;
1335 otmp->owt = weight(otmp);
1336 }
1337 otmp->corpsenm = NON_PM;
1338 otmp->spe = 0;
1339
1340 /* now change it into something layed by the hero */
1341 while (tryct--) {
1342 mnum = can_be_hatched(random_monster());
1343 if (mnum != NON_PM && !dead_species(mnum, TRUE)) {
1344 otmp->spe = 1; /* layed by hero */
1345 otmp->corpsenm = mnum;
1346 attach_egg_hatch_timeout(otmp);
1347 break;
1348 }
1349 }
1350 }
1351
1352 /* keep special fields (including charges on wands) */
1353 if (index(charged_objs, otmp->oclass)) otmp->spe = obj->spe;
1354 otmp->recharged = obj->recharged;
1355
1356 otmp->cursed = obj->cursed;
1357 otmp->blessed = obj->blessed;
1358 otmp->oeroded = obj->oeroded;
1359 otmp->oeroded2 = obj->oeroded2;
1360 if (!is_flammable(otmp) && !is_rustprone(otmp)) otmp->oeroded = 0;
1361 if (!is_corrodeable(otmp) && !is_rottable(otmp)) otmp->oeroded2 = 0;
1362 if (is_damageable(otmp))
1363 otmp->oerodeproof = obj->oerodeproof;
1364
1365 /* Keep chest/box traps and poisoned ammo if we may */
1366 if (obj->otrapped && Is_box(otmp)) otmp->otrapped = TRUE;
1367
1368 if (obj->opoisoned && is_poisonable(otmp))
1369 otmp->opoisoned = TRUE;
1370
1371 if (id == STRANGE_OBJECT && obj->otyp == CORPSE) {
1372 /* turn crocodile corpses into shoes */
1373 if (obj->corpsenm == PM_CROCODILE) {
1374 otmp->otyp = LOW_BOOTS;
1375 otmp->oclass = ARMOR_CLASS;
1376 otmp->spe = 0;
1377 otmp->oeroded = 0;
1378 otmp->oerodeproof = TRUE;
1379 otmp->quan = 1L;
1380 otmp->cursed = FALSE;
1381 }
1382 }
1383
1384 /* no box contents --KAA */
1385 if (Has_contents(otmp)) delete_contents(otmp);
1386
1387 /* 'n' merged objects may be fused into 1 object */
1388 if (otmp->quan > 1L && (!objects[otmp->otyp].oc_merge ||
1389 (can_merge && otmp->quan > (long)rn2(1000))))
1390 otmp->quan = 1L;
1391
1392 switch (otmp->oclass) {
1393
1394 case TOOL_CLASS:
1395 if (otmp->otyp == MAGIC_MARKER) {
1396 otmp->recharged = 1; /* degraded quality */
1397 }
1398 /* don't care about the recharge count of other tools */
1399 break;
1400
1401 case WAND_CLASS:
1402 while (otmp->otyp == WAN_WISHING || otmp->otyp == WAN_POLYMORPH)
1403 otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
1404 /* altering the object tends to degrade its quality
1405 (analogous to spellbook `read count' handling) */
1406 if ((int)otmp->recharged < rn2(7)) /* recharge_limit */
1407 otmp->recharged++;
1408 break;
1409
1410 case POTION_CLASS:
1411 while (otmp->otyp == POT_POLYMORPH)
1412 otmp->otyp = rnd_class(POT_GAIN_ABILITY, POT_WATER);
1413 break;
1414
1415 case SPBOOK_CLASS:
1416 while (otmp->otyp == SPE_POLYMORPH)
1417 otmp->otyp = rnd_class(SPE_DIG, SPE_BLANK_PAPER);
1418 /* reduce spellbook abuse */
1419 otmp->spestudied = obj->spestudied + 1;
1420 break;
1421
1422 case GEM_CLASS:
1423 if (otmp->quan > (long) rnd(4) &&
1424 objects[obj->otyp].oc_material == MINERAL &&
1425 objects[otmp->otyp].oc_material != MINERAL) {
1426 otmp->otyp = ROCK; /* transmutation backfired */
1427 otmp->quan /= 2L; /* some material has been lost */
1428 }
1429 break;
1430 }
1431
1432 /* update the weight */
1433 otmp->owt = weight(otmp);
1434
1435 /* for now, take off worn items being polymorphed */
1436 if (obj_location == OBJ_INVENT) {
1437 if (id == STRANGE_OBJECT)
1438 remove_worn_item(obj, TRUE);
1439 else {
1440 /* This is called only for stone to flesh. It's a lot simpler
1441 * than it otherwise might be. We don't need to check for
1442 * special effects when putting them on (no meat objects have
1443 * any) and only three worn masks are possible.
1444 */
1445 otmp->owornmask = obj->owornmask;
1446 remove_worn_item(obj, TRUE);
1447 setworn(otmp, otmp->owornmask);
1448 if (otmp->owornmask & LEFT_RING)
1449 uleft = otmp;
1450 if (otmp->owornmask & RIGHT_RING)
1451 uright = otmp;
1452 if (otmp->owornmask & W_WEP)
1453 uwep = otmp;
1454 if (otmp->owornmask & W_SWAPWEP)
1455 uswapwep = otmp;
1456 if (otmp->owornmask & W_QUIVER)
1457 uquiver = otmp;
1458 goto no_unwear;
1459 }
1460 }
1461
1462 /* preserve the mask in case being used by something else */
1463 otmp->owornmask = obj->owornmask;
1464 no_unwear:
1465
1466 if (obj_location == OBJ_FLOOR && obj->otyp == BOULDER &&
1467 otmp->otyp != BOULDER)
1468 unblock_point(obj->ox, obj->oy);
1469
1470 /* ** we are now done adjusting the object ** */
1471
1472
1473 /* swap otmp for obj */
1474 replace_object(obj, otmp);
1475 if (obj_location == OBJ_INVENT) {
1476 /*
1477 * We may need to do extra adjustments for the hero if we're
1478 * messing with the hero's inventory. The following calls are
1479 * equivalent to calling freeinv on obj and addinv on otmp,
1480 * while doing an in-place swap of the actual objects.
1481 */
1482 freeinv_core(obj);
1483 addinv_core1(otmp);
1484 addinv_core2(otmp);
1485 }
1486
1487 if ((!carried(otmp) || obj->unpaid) &&
1488 get_obj_location(otmp, &ox, &oy, BURIED_TOO|CONTAINED_TOO) &&
1489 costly_spot(ox, oy)) {
1490 register struct monst *shkp =
1491 shop_keeper(*in_rooms(ox, oy, SHOPBASE));
1492
1493 if ((!obj->no_charge ||
1494 (Has_contents(obj) &&
1495 (contained_cost(obj, shkp, 0L, FALSE, FALSE) != 0L)))
1496 && inhishop(shkp)) {
1497 if(shkp->mpeaceful) {
1498 if(*u.ushops && *in_rooms(u.ux, u.uy, 0) ==
1499 *in_rooms(shkp->mx, shkp->my, 0) &&
1500 !costly_spot(u.ux, u.uy))
1501 make_angry_shk(shkp, ox, oy);
1502 else {
1503 pline("%s gets angry!", Monnam(shkp));
1504 hot_pursuit(shkp);
1505 }
1506 } else Norep("%s is furious!", Monnam(shkp));
1507 }
1508 }
1509 delobj(obj);
1510 return otmp;
1511 }
1512
1513 /*
1514 * Object obj was hit by the effect of the wand/spell otmp. Return
1515 * non-zero if the wand/spell had any effect.
1516 */
1517 int
bhito(obj,otmp)1518 bhito(obj, otmp)
1519 struct obj *obj, *otmp;
1520 {
1521 int res = 1; /* affected object by default */
1522 xchar refresh_x, refresh_y;
1523
1524 if (obj->bypass) {
1525 /* The bypass bit is currently only used as follows:
1526 *
1527 * POLYMORPH - When a monster being polymorphed drops something
1528 * from its inventory as a result of the change.
1529 * If the items fall to the floor, they are not
1530 * subject to direct subsequent polymorphing
1531 * themselves on that same zap. This makes it
1532 * consistent with items that remain in the
1533 * monster's inventory. They are not polymorphed
1534 * either.
1535 * UNDEAD_TURNING - When an undead creature gets killed via
1536 * undead turning, prevent its corpse from being
1537 * immediately revived by the same effect.
1538 *
1539 * The bypass bit on all objects is reset each turn, whenever
1540 * flags.bypasses is set.
1541 *
1542 * We check the obj->bypass bit above AND flags.bypasses
1543 * as a safeguard against any stray occurrence left in an obj
1544 * struct someplace, although that should never happen.
1545 */
1546 if (flags.bypasses)
1547 return 0;
1548 else {
1549 #ifdef DEBUG
1550 pline("%s for a moment.", Tobjnam(obj, "pulsate"));
1551 #endif
1552 obj->bypass = 0;
1553 }
1554 }
1555
1556 /*
1557 * Some parts of this function expect the object to be on the floor
1558 * obj->{ox,oy} to be valid. The exception to this (so far) is
1559 * for the STONE_TO_FLESH spell.
1560 */
1561 if (!(obj->where == OBJ_FLOOR || otmp->otyp == SPE_STONE_TO_FLESH))
1562 warning("bhito: obj is not floor or Stone To Flesh spell");
1563
1564 if (obj == uball) {
1565 res = 0;
1566 } else if (obj == uchain) {
1567 if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) {
1568 unpunish();
1569 makeknown(otmp->otyp);
1570 } else
1571 res = 0;
1572 } else
1573 switch(otmp->otyp) {
1574 case WAN_POLYMORPH:
1575 case SPE_POLYMORPH:
1576 if (obj->otyp == WAN_POLYMORPH ||
1577 obj->otyp == SPE_POLYMORPH ||
1578 obj->otyp == POT_POLYMORPH ||
1579 obj->otyp == AMULET_OF_UNCHANGING ||
1580 obj_resists(obj, 5, 95)) {
1581 res = 0;
1582 break;
1583 }
1584 /* KMH, conduct */
1585 u.uconduct.polypiles++;
1586 /* any saved lock context will be dangerously obsolete */
1587 if (Is_box(obj)) (void) boxlock(obj, otmp);
1588
1589 if (obj_shudders(obj)) {
1590 if (cansee(obj->ox, obj->oy))
1591 makeknown(otmp->otyp);
1592 do_osshock(obj);
1593 break;
1594 }
1595 obj = poly_obj(obj, STRANGE_OBJECT);
1596 newsym(obj->ox,obj->oy);
1597 break;
1598 case WAN_PROBING:
1599 res = !obj->dknown;
1600 /* target object has now been "seen (up close)" */
1601 obj->dknown = 1;
1602 if (Is_container(obj) || obj->otyp == STATUE) {
1603 if (!obj->cobj)
1604 pline("%s empty.", Tobjnam(obj, "are"));
1605 else {
1606 struct obj *o;
1607 /* view contents (not recursively) */
1608 for (o = obj->cobj; o; o = o->nobj)
1609 o->dknown = 1; /* "seen", even if blind */
1610 (void) display_cinventory(obj);
1611 }
1612 res = 1;
1613 }
1614 if (res) makeknown(WAN_PROBING);
1615 break;
1616 case WAN_STRIKING:
1617 case SPE_FORCE_BOLT:
1618 if (obj->otyp == BOULDER)
1619 fracture_rock(obj);
1620 else if (obj->otyp == STATUE)
1621 (void) break_statue(obj);
1622 else {
1623 if (!flags.mon_moving)
1624 (void)hero_breaks(obj, obj->ox, obj->oy, FALSE);
1625 else
1626 (void)breaks(obj, obj->ox, obj->oy);
1627 res = 0;
1628 }
1629 /* BUG[?]: shouldn't this depend upon you seeing it happen? */
1630 makeknown(otmp->otyp);
1631 break;
1632 case WAN_CANCELLATION:
1633 case SPE_CANCELLATION:
1634 cancel_item(obj);
1635 #ifdef TEXTCOLOR
1636 newsym(obj->ox,obj->oy); /* might change color */
1637 #endif
1638 break;
1639 case SPE_DRAIN_LIFE:
1640 (void) drain_item(obj);
1641 break;
1642 case WAN_TELEPORTATION:
1643 case SPE_TELEPORT_AWAY:
1644 rloco(obj);
1645 break;
1646 case WAN_MAKE_INVISIBLE:
1647 #ifdef INVISIBLE_OBJECTS
1648 obj->oinvis = TRUE;
1649 newsym(obj->ox,obj->oy); /* make object disappear */
1650 #endif
1651 break;
1652 case WAN_UNDEAD_TURNING:
1653 case SPE_TURN_UNDEAD:
1654 if (obj->otyp == EGG)
1655 revive_egg(obj);
1656 else
1657 res = !!revive(obj);
1658 break;
1659 case WAN_OPENING:
1660 case SPE_KNOCK:
1661 case WAN_LOCKING:
1662 case SPE_WIZARD_LOCK:
1663 if(Is_box(obj))
1664 res = boxlock(obj, otmp);
1665 else
1666 res = 0;
1667 if (res /* && otmp->oclass == WAND_CLASS */)
1668 makeknown(otmp->otyp);
1669 break;
1670 case WAN_SLOW_MONSTER: /* no effect on objects */
1671 case SPE_SLOW_MONSTER:
1672 case WAN_SPEED_MONSTER:
1673 case WAN_NOTHING:
1674 case SPE_HEALING:
1675 case SPE_EXTRA_HEALING:
1676 case WAN_SLEEP:
1677 res = 0;
1678 break;
1679 case SPE_STONE_TO_FLESH:
1680 refresh_x = obj->ox; refresh_y = obj->oy;
1681 if (objects[obj->otyp].oc_material != MINERAL &&
1682 objects[obj->otyp].oc_material != GEMSTONE) {
1683 res = 0;
1684 break;
1685 }
1686 /* add more if stone objects are added.. */
1687 switch (objects[obj->otyp].oc_class) {
1688 case ROCK_CLASS: /* boulders and statues */
1689 if (obj->otyp == BOULDER) {
1690 obj = poly_obj(obj, HUGE_CHUNK_OF_MEAT);
1691 goto smell;
1692 } else if (obj->otyp == STATUE) {
1693 xchar oox, ooy;
1694
1695 (void) get_obj_location(obj, &oox, &ooy, 0);
1696 refresh_x = oox; refresh_y = ooy;
1697 if (vegetarian(&mons[obj->corpsenm])) {
1698 /* Don't animate monsters that aren't flesh */
1699 obj = poly_obj(obj, MEATBALL);
1700 goto smell;
1701 }
1702 if (!animate_statue(obj, oox, ooy,
1703 ANIMATE_SPELL, (int *)0)) {
1704 struct obj *item;
1705 makecorpse: if (mons[obj->corpsenm].geno &
1706 (G_NOCORPSE|G_UNIQ)) {
1707 res = 0;
1708 break;
1709 }
1710 /* Unlikely to get here since genociding
1711 * monsters also sets the G_NOCORPSE flag.
1712 * Drop the contents, poly_obj looses them.
1713 */
1714 while ((item = obj->cobj) != 0) {
1715 obj_extract_self(item);
1716 place_object(item, oox, ooy);
1717 }
1718 obj = poly_obj(obj, CORPSE);
1719 break;
1720 }
1721 } else { /* new rock class object... */
1722 /* impossible? */
1723 res = 0;
1724 }
1725 break;
1726 case TOOL_CLASS: /* figurine */
1727 {
1728 struct monst *mon;
1729 xchar oox, ooy;
1730
1731 if (obj->otyp != FIGURINE) {
1732 res = 0;
1733 break;
1734 }
1735 if (vegetarian(&mons[obj->corpsenm])) {
1736 /* Don't animate monsters that aren't flesh */
1737 obj = poly_obj(obj, MEATBALL);
1738 goto smell;
1739 }
1740 (void) get_obj_location(obj, &oox, &ooy, 0);
1741 refresh_x = oox; refresh_y = ooy;
1742 mon = makemon(&mons[obj->corpsenm],
1743 oox, ooy, NO_MM_FLAGS);
1744 if (mon) {
1745 delobj(obj);
1746 if (cansee(mon->mx, mon->my))
1747 pline_The("figurine animates!");
1748 break;
1749 }
1750 goto makecorpse;
1751 }
1752 /* maybe add weird things to become? */
1753 case RING_CLASS: /* some of the rings are stone */
1754 obj = poly_obj(obj, MEAT_RING);
1755 goto smell;
1756 case WAND_CLASS: /* marble wand */
1757 obj = poly_obj(obj, MEAT_STICK);
1758 goto smell;
1759 case GEM_CLASS: /* rocks & gems */
1760 obj = poly_obj(obj, MEATBALL);
1761 smell:
1762 if (herbivorous(youmonst.data) &&
1763 (!carnivorous(youmonst.data) ||
1764 Role_if(PM_MONK) || !u.uconduct.unvegetarian))
1765 Norep("You smell the odor of meat.");
1766 else
1767 Norep("You smell a delicious smell.");
1768 break;
1769 case WEAPON_CLASS: /* crysknife */
1770 /* fall through */
1771 default:
1772 res = 0;
1773 break;
1774 }
1775 newsym(refresh_x, refresh_y);
1776 break;
1777 default:
1778 warning("What an interesting effect (%d)", otmp->otyp);
1779 break;
1780 }
1781 return res;
1782 }
1783
1784 /* returns nonzero if something was hit */
1785 int
bhitpile(obj,fhito,tx,ty)1786 bhitpile(obj,fhito,tx,ty)
1787 struct obj *obj;
1788 int FDECL((*fhito), (OBJ_P,OBJ_P));
1789 int tx, ty;
1790 {
1791 int hitanything = 0;
1792 register struct obj *otmp, *next_obj;
1793
1794 if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) {
1795 struct trap *t = t_at(tx, ty);
1796
1797 /* We can't settle for the default calling sequence of
1798 bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
1799 because that last call might end up operating on our `next_obj'
1800 (below), rather than on the current object, if it happens to
1801 encounter a statue which mustn't become animated. */
1802 if (t && t->ttyp == STATUE_TRAP &&
1803 activate_statue_trap(t, tx, ty, TRUE) && obj->otyp == WAN_STRIKING)
1804 makeknown(obj->otyp);
1805 }
1806
1807 poly_zapped = -1;
1808 for(otmp = level.objects[tx][ty]; otmp; otmp = next_obj) {
1809 /* Fix for polymorph bug, Tim Wright */
1810 next_obj = otmp->nexthere;
1811 hitanything += (*fhito)(otmp, obj);
1812 }
1813 if(poly_zapped >= 0)
1814 create_polymon(level.objects[tx][ty], poly_zapped);
1815
1816 return hitanything;
1817 }
1818
1819 /*
1820 * zappable - returns 1 if zap is available, 0 otherwise.
1821 * it removes a charge from the wand if zappable.
1822 * added by GAN 11/03/86
1823 */
1824 int
zappable(wand)1825 zappable(wand)
1826 register struct obj *wand;
1827 {
1828 if(wand->spe < 0 || (wand->spe == 0 && rn2(121)))
1829 return 0;
1830 if(wand->spe == 0)
1831 You("wrest one last charge from the worn-out wand.");
1832 wand->spe--;
1833 return 1;
1834 }
1835
1836 /*
1837 * zapnodir - zaps a NODIR wand/spell.
1838 * added by GAN 11/03/86
1839 */
1840 void
zapnodir(obj)1841 zapnodir(obj)
1842 register struct obj *obj;
1843 {
1844 boolean known = FALSE;
1845
1846 switch(obj->otyp) {
1847 case WAN_LIGHT:
1848 case SPE_LIGHT:
1849 litroom(TRUE,obj);
1850 if (!Blind) known = TRUE;
1851 break;
1852 case WAN_SECRET_DOOR_DETECTION:
1853 case SPE_DETECT_UNSEEN:
1854 if(!findit()) return;
1855 if (!Blind) known = TRUE;
1856 break;
1857 case WAN_CREATE_MONSTER:
1858 known = create_critters(rn2(23) ? 1 : rn1(7,2),
1859 (struct permonst *)0);
1860 break;
1861 case WAN_WISHING:
1862 known = TRUE;
1863 if(Luck + rn2(5) < 0) {
1864 pline("Unfortunately, nothing happens.");
1865 break;
1866 }
1867 makewish(TRUE);
1868 break;
1869 case WAN_ENLIGHTENMENT:
1870 known = TRUE;
1871 You_feel("self-knowledgeable...");
1872 display_nhwindow(WIN_MESSAGE, FALSE);
1873 enlightenment(FALSE, TRUE);
1874 pline_The("feeling subsides.");
1875 exercise(A_WIS, TRUE);
1876 break;
1877 }
1878 if (known && !objects[obj->otyp].oc_name_known) {
1879 makeknown(obj->otyp);
1880 more_experienced(0,0,10);
1881 }
1882 }
1883
1884 STATIC_OVL void
backfire(otmp)1885 backfire(otmp)
1886 struct obj *otmp;
1887 {
1888 otmp->in_use = TRUE; /* in case losehp() is fatal */
1889 pline("%s suddenly explodes!", The(xname(otmp)));
1890 losehp(d(otmp->spe+2,6), "exploding wand", KILLED_BY_AN);
1891 useup(otmp);
1892 }
1893
1894 static NEARDATA const char zap_syms[] = { WAND_CLASS, 0 };
1895
1896 int
dozap()1897 dozap()
1898 {
1899 register struct obj *obj;
1900 int damage;
1901
1902 if(check_capacity((char *)0)) return(0);
1903 obj = getobj(zap_syms, "zap");
1904 if(!obj) return(0);
1905
1906 check_unpaid(obj);
1907
1908 /* zappable addition done by GAN 11/03/86 */
1909 if(!zappable(obj)) {
1910 pline("%s", nothing_happens);
1911 /* if nameempty is set, then #name unnamed known empty wands */
1912 if (iflags.nameempty && !obj->onamelth) oname(obj, iflags.nameempty);
1913 }
1914 /* PM 2008-04-16: 50% chance of blowing up, if zapped 20 times.
1915 * Same probability as in muse.c precheck() for monsters */
1916 else if (obj->cursed && !rn2(30)) {
1917 backfire(obj); /* the wand blows up in your face! */
1918 exercise(A_STR, FALSE);
1919 return(1);
1920 } else if(!(objects[obj->otyp].oc_dir == NODIR) && !getdir((char *)0)) {
1921 if (!Blind)
1922 pline("%s glows and fades.", The(xname(obj)));
1923 /* make him pay for knowing !NODIR */
1924 } else if(!u.dx && !u.dy && !u.dz && !(objects[obj->otyp].oc_dir == NODIR)) {
1925 if ((damage = zapyourself(obj, TRUE)) != 0) {
1926 char buf[BUFSZ];
1927 Sprintf(buf, "zapped %sself with a wand", uhim());
1928 losehp(damage, buf, NO_KILLER_PREFIX);
1929 }
1930 } else {
1931
1932 /* Are we having fun yet?
1933 * weffects -> buzz(obj->otyp) -> zhitm (temple priest) ->
1934 * attack -> hitum -> known_hitum -> ghod_hitsu ->
1935 * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) ->
1936 * useup -> obfree -> dealloc_obj -> free(obj)
1937 */
1938 current_wand = obj;
1939 weffects(obj);
1940 obj = current_wand;
1941 current_wand = 0;
1942 }
1943 if (obj && obj->spe < 0) {
1944 pline("%s to dust.", Tobjnam(obj, "turn"));
1945 useup(obj);
1946 }
1947 update_inventory(); /* maybe used a charge */
1948 return(1);
1949 }
1950
1951 int
zapyourself(obj,ordinary)1952 zapyourself(obj, ordinary)
1953 struct obj *obj;
1954 boolean ordinary;
1955 {
1956 int damage = 0;
1957 char buf[BUFSZ];
1958
1959 switch(obj->otyp) {
1960 case WAN_STRIKING:
1961 makeknown(WAN_STRIKING);
1962 case SPE_FORCE_BOLT:
1963 if(Antimagic) {
1964 shieldeff(u.ux, u.uy);
1965 pline("Boing!");
1966 } else {
1967 if (ordinary) {
1968 You("bash yourself!");
1969 damage = d(2,12);
1970 } else
1971 damage = d(1 + obj->spe,6);
1972 exercise(A_STR, FALSE);
1973 }
1974 break;
1975
1976 case WAN_LIGHTNING:
1977 makeknown(WAN_LIGHTNING);
1978 if (!Shock_resistance) {
1979 You("shock yourself!");
1980 damage = d(12,6);
1981 exercise(A_CON, FALSE);
1982 } else {
1983 shieldeff(u.ux, u.uy);
1984 You("zap yourself, but seem unharmed.");
1985 ugolemeffects(AD_ELEC, d(12,6));
1986 }
1987 destroy_item(WAND_CLASS, AD_ELEC);
1988 destroy_item(RING_CLASS, AD_ELEC);
1989 if (!resists_blnd(&youmonst)) {
1990 You(are_blinded_by_the_flash);
1991 make_blinded((long)rnd(100),FALSE);
1992 if (!Blind) Your("%s", vision_clears);
1993 }
1994 break;
1995
1996 case SPE_FIREBALL:
1997 You("explode a fireball on top of yourself!");
1998 explode(u.ux, u.uy, 11, d(6,6), WAND_CLASS, EXPL_FIERY);
1999 break;
2000 case WAN_FIRE:
2001 makeknown(WAN_FIRE);
2002 case FIRE_HORN:
2003 if (Fire_resistance) {
2004 shieldeff(u.ux, u.uy);
2005 You_feel("rather warm.");
2006 ugolemeffects(AD_FIRE, d(12,6));
2007 } else {
2008 pline("You've set yourself afire!");
2009 damage = d(12,6);
2010 }
2011 burn_away_slime();
2012 (void) burnarmor(&youmonst);
2013 destroy_item(SCROLL_CLASS, AD_FIRE);
2014 destroy_item(POTION_CLASS, AD_FIRE);
2015 destroy_item(SPBOOK_CLASS, AD_FIRE);
2016 break;
2017
2018 case WAN_COLD:
2019 makeknown(WAN_COLD);
2020 case SPE_CONE_OF_COLD:
2021 case FROST_HORN:
2022 if (Cold_resistance) {
2023 shieldeff(u.ux, u.uy);
2024 You_feel("a little chill.");
2025 ugolemeffects(AD_COLD, d(12,6));
2026 } else {
2027 You("imitate a popsicle!");
2028 damage = d(12,6);
2029 }
2030 destroy_item(POTION_CLASS, AD_COLD);
2031 break;
2032
2033 case WAN_MAGIC_MISSILE:
2034 makeknown(WAN_MAGIC_MISSILE);
2035 case SPE_MAGIC_MISSILE:
2036 if(Antimagic) {
2037 shieldeff(u.ux, u.uy);
2038 pline_The("missiles bounce!");
2039 } else {
2040 damage = d(4,6);
2041 pline("Idiot! You've shot yourself!");
2042 }
2043 break;
2044
2045 case WAN_POLYMORPH:
2046 if (!Unchanging)
2047 makeknown(WAN_POLYMORPH);
2048 case SPE_POLYMORPH:
2049 if (!Unchanging)
2050 polyself(FALSE);
2051 break;
2052
2053 case WAN_CANCELLATION:
2054 case SPE_CANCELLATION:
2055 (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE);
2056 break;
2057
2058 case SPE_DRAIN_LIFE:
2059 if (!Drain_resistance) {
2060 losexp("life drainage");
2061 makeknown(obj->otyp);
2062 }
2063 damage = 0; /* No additional damage */
2064 break;
2065
2066 case WAN_MAKE_INVISIBLE: {
2067 /* have to test before changing HInvis but must change
2068 * HInvis before doing newsym().
2069 */
2070 int msg = !Invis && !Blind && !BInvis;
2071
2072 if (BInvis && uarmc->otyp == MUMMY_WRAPPING) {
2073 /* A mummy wrapping absorbs it and protects you */
2074 You_feel("rather itchy under your %s.", xname(uarmc));
2075 break;
2076 }
2077 if (ordinary || !rn2(10)) { /* permanent */
2078 HInvis |= FROMOUTSIDE;
2079 } else { /* temporary */
2080 incr_itimeout(&HInvis, d(obj->spe, 250));
2081 }
2082 if (msg) {
2083 makeknown(WAN_MAKE_INVISIBLE);
2084 newsym(u.ux, u.uy);
2085 self_invis_message();
2086 }
2087 break;
2088 }
2089
2090 case WAN_SPEED_MONSTER:
2091 if (!(HFast & INTRINSIC)) {
2092 if (!Fast)
2093 You("speed up.");
2094 else
2095 Your("quickness feels more natural.");
2096 makeknown(WAN_SPEED_MONSTER);
2097 exercise(A_DEX, TRUE);
2098 }
2099 HFast |= FROMOUTSIDE;
2100 break;
2101
2102 case WAN_SLEEP:
2103 makeknown(WAN_SLEEP);
2104 case SPE_SLEEP:
2105 if(Sleep_resistance) {
2106 shieldeff(u.ux, u.uy);
2107 You("don't feel sleepy!");
2108 } else {
2109 pline_The("sleep ray hits you!");
2110 fall_asleep(-rnd(50), TRUE);
2111 }
2112 break;
2113
2114 case WAN_SLOW_MONSTER:
2115 case SPE_SLOW_MONSTER:
2116 if(HFast & (TIMEOUT | INTRINSIC)) {
2117 u_slow_down();
2118 makeknown(obj->otyp);
2119 }
2120 break;
2121
2122 case WAN_TELEPORTATION:
2123 makeknown(WAN_TELEPORTATION);
2124 case SPE_TELEPORT_AWAY:
2125 tele();
2126 break;
2127
2128 case WAN_DEATH:
2129 case SPE_FINGER_OF_DEATH:
2130 if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
2131 pline((obj->otyp == WAN_DEATH) ?
2132 "The wand shoots an apparently harmless beam at you."
2133 : "You seem no deader than before.");
2134 break;
2135 }
2136 Sprintf(buf, "shot %sself with a death ray", uhim());
2137 killer = buf;
2138 killer_format = NO_KILLER_PREFIX;
2139 You("irradiate yourself with pure energy!");
2140 You("die.");
2141 makeknown(obj->otyp);
2142 /* They might survive with an amulet of life saving */
2143 done(DIED);
2144 break;
2145 case WAN_UNDEAD_TURNING:
2146 makeknown(WAN_UNDEAD_TURNING);
2147 case SPE_TURN_UNDEAD:
2148 (void) unturn_dead(&youmonst);
2149 if (is_undead(youmonst.data)) {
2150 You_feel("frightened and %sstunned.",
2151 Stunned ? "even more " : "");
2152 make_stunned(HStun + rnd(30), FALSE);
2153 } else
2154 You("shudder in dread.");
2155 break;
2156 case SPE_HEALING:
2157 case SPE_EXTRA_HEALING:
2158 healup(d(6, obj->otyp == SPE_EXTRA_HEALING ? 8 : 4),
2159 0, FALSE, (obj->otyp == SPE_EXTRA_HEALING));
2160 You_feel("%sbetter.",
2161 obj->otyp == SPE_EXTRA_HEALING ? "much " : "");
2162 break;
2163 case WAN_LIGHT: /* (broken wand) */
2164 /* assert( !ordinary ); */
2165 damage = d(obj->spe, 25);
2166 #ifdef TOURIST
2167 case EXPENSIVE_CAMERA:
2168 #endif
2169 damage += rnd(25);
2170 if (!resists_blnd(&youmonst)) {
2171 You(are_blinded_by_the_flash);
2172 make_blinded((long)damage, FALSE);
2173 makeknown(obj->otyp);
2174 if (!Blind) Your("%s", vision_clears);
2175 }
2176 damage = 0; /* reset */
2177 break;
2178 case WAN_OPENING:
2179 if (Punished) makeknown(WAN_OPENING);
2180 case SPE_KNOCK:
2181 if (Punished) Your("chain quivers for a moment.");
2182 break;
2183 case WAN_DIGGING:
2184 case SPE_DIG:
2185 case SPE_DETECT_UNSEEN:
2186 case WAN_NOTHING:
2187 case WAN_LOCKING:
2188 case SPE_WIZARD_LOCK:
2189 break;
2190 case WAN_PROBING:
2191 /* identify type of dragon when probing */
2192 if (Upolyd && (monsndx(youmonst.data) >= PM_BABY_GRAY_DRAGON &&
2193 monsndx(youmonst.data) <= PM_YELLOW_DRAGON)) {
2194 if (monsndx(youmonst.data) < PM_GRAY_DRAGON) {
2195 identify_dragon(monsndx(youmonst.data) - PM_BABY_GRAY_DRAGON);
2196 } else {
2197 identify_dragon(monsndx(youmonst.data) - PM_GRAY_DRAGON);
2198 }
2199 }
2200 for (obj = invent; obj; obj = obj->nobj)
2201 obj->dknown = 1;
2202 /* note: `obj' reused; doesn't point at wand anymore */
2203 makeknown(WAN_PROBING);
2204 ustatusline();
2205 break;
2206 case SPE_STONE_TO_FLESH:
2207 {
2208 struct obj *otemp, *onext;
2209 boolean didmerge;
2210
2211 if (u.umonnum == PM_STONE_GOLEM)
2212 (void) polymon(PM_FLESH_GOLEM);
2213 if (Stoned) fix_petrification(); /* saved! */
2214 /* but at a cost.. */
2215 for (otemp = invent; otemp; otemp = onext) {
2216 onext = otemp->nobj;
2217 (void) bhito(otemp, obj);
2218 }
2219 /*
2220 * It is possible that we can now merge some inventory.
2221 * Do a higly paranoid merge. Restart from the beginning
2222 * until no merges.
2223 */
2224 do {
2225 didmerge = FALSE;
2226 for (otemp = invent; !didmerge && otemp; otemp = otemp->nobj)
2227 for (onext = otemp->nobj; onext; onext = onext->nobj)
2228 if (merged(&otemp, &onext)) {
2229 didmerge = TRUE;
2230 break;
2231 }
2232 } while (didmerge);
2233 }
2234 break;
2235 default: warning("object %d used?",obj->otyp);
2236 break;
2237 }
2238 return(damage);
2239 }
2240
2241 #ifdef STEED
2242 /* you've zapped a wand downwards while riding
2243 * Return TRUE if the steed was hit by the wand.
2244 * Return FALSE if the steed was not hit by the wand.
2245 */
2246 STATIC_OVL boolean
zap_steed(obj)2247 zap_steed(obj)
2248 struct obj *obj; /* wand or spell */
2249 {
2250 int steedhit = FALSE;
2251
2252 switch (obj->otyp) {
2253
2254 /*
2255 * Wands that are allowed to hit the steed
2256 * Carefully test the results of any that are
2257 * moved here from the bottom section.
2258 */
2259 case WAN_PROBING:
2260 probe_monster(u.usteed);
2261 makeknown(WAN_PROBING);
2262 steedhit = TRUE;
2263 break;
2264 case WAN_TELEPORTATION:
2265 makeknown(WAN_TELEPORTATION);
2266 case SPE_TELEPORT_AWAY:
2267 /* you go together */
2268 tele();
2269 if(Teleport_control || !couldsee(u.ux0, u.uy0) ||
2270 (distu(u.ux0, u.uy0) >= 16))
2271 makeknown(obj->otyp);
2272 steedhit = TRUE;
2273 break;
2274
2275 /* Default processing via bhitm() for these */
2276 case SPE_CURE_SICKNESS:
2277 case WAN_MAKE_INVISIBLE:
2278 case WAN_CANCELLATION:
2279 case SPE_CANCELLATION:
2280 case WAN_POLYMORPH:
2281 case SPE_POLYMORPH:
2282 case WAN_STRIKING:
2283 case SPE_FORCE_BOLT:
2284 case WAN_SLOW_MONSTER:
2285 case SPE_SLOW_MONSTER:
2286 case WAN_SPEED_MONSTER:
2287 case SPE_HEALING:
2288 case SPE_EXTRA_HEALING:
2289 case SPE_DRAIN_LIFE:
2290 case WAN_OPENING:
2291 case SPE_KNOCK:
2292 (void) bhitm(u.usteed, obj);
2293 steedhit = TRUE;
2294 break;
2295
2296 default:
2297 steedhit = FALSE;
2298 break;
2299 }
2300 return steedhit;
2301 }
2302 #endif
2303
2304 /*
2305 * cancel a monster (possibly the hero). inventory is cancelled only
2306 * if the monster is zapping itself directly, since otherwise the
2307 * effect is too strong. currently non-hero monsters do not zap
2308 * themselves with cancellation.
2309 */
2310 boolean
cancel_monst(mdef,obj,youattack,allow_cancel_kill,self_cancel)2311 cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel)
2312 register struct monst *mdef;
2313 register struct obj *obj;
2314 boolean youattack, allow_cancel_kill, self_cancel;
2315 {
2316 boolean youdefend = (mdef == &youmonst);
2317 static const char writing_vanishes[] =
2318 "Some writing vanishes from %s head!";
2319 static const char your[] = "your"; /* should be extern */
2320
2321 if (youdefend)
2322 You(!Hallucination? "are covered in sparkling lights!"
2323 : "are enveloped by psychedelic fireworks!");
2324
2325 if (youdefend ? (!youattack && Antimagic)
2326 : resist(mdef, obj->oclass, 0, NOTELL))
2327 return FALSE; /* resisted cancellation */
2328
2329 if (self_cancel) { /* 1st cancel inventory */
2330 struct obj *otmp;
2331
2332 for (otmp = (youdefend ? invent : mdef->minvent);
2333 otmp; otmp = otmp->nobj)
2334 cancel_item(otmp);
2335 if (youdefend) {
2336 flags.botl = 1; /* potential AC change */
2337 find_ac();
2338 }
2339 } else if (!(obj && (obj->oartifact == ART_MAGICBANE))) { /* Magicbane doesn't cancel inventory items */
2340 /* select one random item to cancel */
2341 struct obj *otmp;
2342 int count = 0;
2343
2344 for (otmp = (youdefend ? invent : mdef->minvent);
2345 otmp; otmp = otmp->nobj) {
2346 if (cancellable(otmp)) {
2347 count++;
2348 }
2349 }
2350
2351 if (count > 0) {
2352 int o = rnd(count);
2353
2354 for (otmp = (youdefend ? invent : mdef->minvent);
2355 otmp; otmp = otmp->nobj) {
2356 if (cancellable(otmp)) {
2357 o--;
2358 if (o == 0) {
2359 cancel_item(otmp);
2360 break;
2361 }
2362 }
2363 }
2364 if (youdefend) {
2365 flags.botl = 1; /* potential AC change */
2366 find_ac();
2367 }
2368 }
2369 }
2370
2371 /* now handle special cases */
2372 if (youdefend) {
2373 if (Upolyd) {
2374 if ((u.umonnum == PM_CLAY_GOLEM) && !Blind)
2375 pline(writing_vanishes, your);
2376
2377 if (Unchanging)
2378 Your("amulet grows hot for a moment, then cools.");
2379 else
2380 rehumanize();
2381 }
2382 } else {
2383 boolean got_cancelled = !mdef->mcan;
2384 mdef->mcan = TRUE;
2385
2386 if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN)
2387 were_change(mdef);
2388
2389 if (mdef->data == &mons[PM_CLAY_GOLEM]) {
2390 if (canseemon(mdef))
2391 pline(writing_vanishes, s_suffix(mon_nam(mdef)));
2392
2393 if (allow_cancel_kill) {
2394 if (youattack)
2395 killed(mdef);
2396 else
2397 monkilled(mdef, "", AD_SPEL);
2398 }
2399 } else if (got_cancelled && canseemon(mdef)) {
2400 const char* msg = (char *)0;
2401 /* this is probably not the proper way of doing it */
2402 int adtyp = mdef->data->mattk[0].adtyp;
2403 int aatyp = mdef->data->mattk[0].aatyp;
2404
2405 if (aatyp != AT_NONE) {
2406 switch (adtyp) {
2407 case AD_COLD:
2408 msg = "warmer";
2409 break;
2410 case AD_FIRE:
2411 msg = "colder";
2412 break;
2413 case AD_CORR:
2414 msg = "less corrosive";
2415 break;
2416 case AD_RUST:
2417 msg = "less rusting";
2418 break;
2419 case AD_ENCH:
2420 msg = "less effective";
2421 break;
2422 case AD_DISN:
2423 msg = "less disintegrative";
2424 break;
2425 case AD_SPOR:
2426 msg = "dormant";
2427 break;
2428 default:
2429 break;
2430 }
2431 if (msg) {
2432 pline("%s seems to be %s!", Monnam(mdef), msg);
2433 /* identify wand if receiving message */
2434 if (obj->otyp == WAN_CANCELLATION) makeknown(obj->otyp);
2435 }
2436 }
2437 }
2438 }
2439 return TRUE;
2440 }
2441
2442 /* you've zapped an immediate type wand up or down */
2443 STATIC_OVL boolean
zap_updown(obj)2444 zap_updown(obj)
2445 struct obj *obj; /* wand or spell */
2446 {
2447 boolean striking = FALSE, disclose = FALSE;
2448 int x, y, xx, yy, ptmp;
2449 struct obj *otmp;
2450 struct engr *e;
2451 struct trap *ttmp;
2452 char buf[BUFSZ];
2453
2454 /* some wands have special effects other than normal bhitpile */
2455 /* drawbridge might change <u.ux,u.uy> */
2456 x = xx = u.ux; /* <x,y> is zap location */
2457 y = yy = u.uy; /* <xx,yy> is drawbridge (portcullis) position */
2458 ttmp = t_at(x, y); /* trap if there is one */
2459
2460 switch (obj->otyp) {
2461 case WAN_PROBING:
2462 ptmp = 0;
2463 if (u.dz < 0) {
2464 You("probe towards the %s.", ceiling(x,y));
2465 } else {
2466 ptmp += bhitpile(obj, bhito, x, y);
2467 You("probe beneath the %s.", surface(x,y));
2468 ptmp += display_binventory(x, y, TRUE);
2469 }
2470 if (!ptmp) Your("probe reveals nothing.");
2471 return TRUE; /* we've done our own bhitpile */
2472 case WAN_OPENING:
2473 case SPE_KNOCK:
2474 /* up or down, but at closed portcullis only */
2475 if (is_db_wall(x,y) && find_drawbridge(&xx, &yy)) {
2476 open_drawbridge(xx, yy);
2477 disclose = TRUE;
2478 } else if (u.dz > 0 && (x == xdnstair && y == ydnstair) &&
2479 /* can't use the stairs down to quest level 2 until
2480 leader "unlocks" them; give feedback if you try */
2481 on_level(&u.uz, &qstart_level) && !ok_to_quest()) {
2482 pline_The("stairs seem to ripple momentarily.");
2483 disclose = TRUE;
2484 }
2485 break;
2486 case WAN_STRIKING:
2487 case SPE_FORCE_BOLT:
2488 striking = TRUE;
2489 /*FALLTHRU*/
2490 case WAN_LOCKING:
2491 case SPE_WIZARD_LOCK:
2492 /* down at open bridge or up or down at open portcullis */
2493 if ((levl[x][y].typ == DRAWBRIDGE_DOWN) ? (u.dz > 0) :
2494 (is_drawbridge_wall(x,y) && !is_db_wall(x,y)) &&
2495 find_drawbridge(&xx, &yy)) {
2496 if (!striking)
2497 close_drawbridge(xx, yy);
2498 else
2499 destroy_drawbridge(xx, yy);
2500 disclose = TRUE;
2501 } else if (striking && u.dz < 0 && rn2(3) &&
2502 !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) &&
2503 !Underwater && !Is_qstart(&u.uz)) {
2504 /* similar to zap_dig() */
2505 pline("A rock is dislodged from the %s and falls on your %s.",
2506 ceiling(x, y), body_part(HEAD));
2507 losehp(rnd((uarmh && is_metallic(uarmh)) ? 2 : 6),
2508 "falling rock", KILLED_BY_AN);
2509 if ((otmp = mksobj_at(ROCK, x, y, FALSE, FALSE)) != 0) {
2510 (void)xname(otmp); /* set dknown, maybe bknown */
2511 stackobj(otmp);
2512 }
2513 newsym(x, y);
2514 } else if (!striking && ttmp && ttmp->ttyp == TRAPDOOR && u.dz > 0) {
2515 if (!Blind) {
2516 if (ttmp->tseen) {
2517 pline("A trap door beneath you closes up then vanishes.");
2518 disclose = TRUE;
2519 } else {
2520 You("see a swirl of %s beneath you.",
2521 is_ice(x,y) ? "frost" : "dust");
2522 }
2523 } else {
2524 You_hear("a twang followed by a thud.");
2525 }
2526 deltrap(ttmp);
2527 ttmp = (struct trap *)0;
2528 newsym(x, y);
2529 }
2530 break;
2531 case SPE_STONE_TO_FLESH:
2532 if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ||
2533 Underwater || (Is_qstart(&u.uz) && u.dz < 0)) {
2534 pline("%s", nothing_happens);
2535 } else if (u.dz < 0) { /* we should do more... */
2536 pline("Blood drips on your %s.", body_part(FACE));
2537 } else if (u.dz > 0 && !OBJ_AT(u.ux, u.uy)) {
2538 /*
2539 Print this message only if there wasn't an engraving
2540 affected here. If water or ice, act like waterlevel case.
2541 */
2542 e = engr_at(u.ux, u.uy);
2543 if (!(e && e->engr_type == ENGRAVE)) {
2544 if (is_pool(u.ux, u.uy) || is_ice(u.ux, u.uy))
2545 pline("%s", nothing_happens);
2546 else
2547 pline("Blood %ss %s your %s.",
2548 is_lava(u.ux, u.uy) ? "boil" : "pool",
2549 Levitation ? "beneath" : "at",
2550 makeplural(body_part(FOOT)));
2551 }
2552 }
2553 break;
2554 default:
2555 break;
2556 }
2557
2558 if (u.dz > 0) {
2559 /* zapping downward */
2560 (void) bhitpile(obj, bhito, x, y);
2561
2562 if (ttmp) {
2563 switch (obj->otyp) {
2564 case WAN_CANCELLATION:
2565 case SPE_CANCELLATION:
2566 /* MRKR: Disarm magical traps */
2567 /* from an idea posted to rgrn by Haakon Studebaker */
2568 if (ttmp->ttyp == MAGIC_TRAP || ttmp->ttyp == TELEP_TRAP ||
2569 ttmp->ttyp == LEVEL_TELEP || ttmp->ttyp == POLY_TRAP ||
2570 ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == ANTI_MAGIC) {
2571 if (ttmp->ttyp != MAGIC_PORTAL && ttmp->ttyp != ANTI_MAGIC) {
2572 if (ttmp->tseen) {
2573 You("disarm a %s.",
2574 defsyms[trap_to_defsym(ttmp->ttyp)].explanation);
2575 deltrap(ttmp);
2576 }
2577 } else {
2578 if (ttmp->tseen) {
2579 You("are mesmerised by%s conflicting magics.",
2580 objects[WAN_CANCELLATION].oc_name_known ? " the" : "");
2581 }
2582 }
2583 if (obj->otyp == WAN_CANCELLATION) makeknown(obj->otyp);
2584 }
2585 break;
2586 default:
2587 break;
2588 }
2589 }
2590 /* subset of engraving effects; none sets `disclose' */
2591 if ((e = engr_at(x, y)) != 0 && e->engr_type != HEADSTONE) {
2592 switch (obj->otyp) {
2593 case WAN_POLYMORPH:
2594 makeknown(obj->otyp);
2595 case SPE_POLYMORPH:
2596 del_engr(e);
2597 make_engr_at(x, y, random_engraving(buf), moves, (xchar)0);
2598 break;
2599 case WAN_CANCELLATION:
2600 case WAN_MAKE_INVISIBLE:
2601 if ((objects[WAN_TELEPORTATION].oc_name_known &&
2602 objects[WAN_CANCELLATION].oc_name_known) ||
2603 (objects[WAN_TELEPORTATION].oc_name_known &&
2604 objects[WAN_MAKE_INVISIBLE].oc_name_known))
2605 makeknown(obj->otyp);
2606 case SPE_CANCELLATION:
2607 del_engr(e);
2608 break;
2609 case WAN_TELEPORTATION:
2610 if (objects[WAN_CANCELLATION].oc_name_known &&
2611 objects[WAN_MAKE_INVISIBLE].oc_name_known)
2612 makeknown(obj->otyp);
2613 case SPE_TELEPORT_AWAY:
2614 rloc_engr(e);
2615 break;
2616 case SPE_STONE_TO_FLESH:
2617 if (e->engr_type == ENGRAVE) {
2618 /* only affects things in stone */
2619 pline_The(Hallucination ?
2620 "floor runs like butter!" :
2621 "edges on the floor get smoother.");
2622 wipe_engr_at(x, y, d(2,4));
2623 }
2624 break;
2625 case WAN_STRIKING:
2626 case SPE_FORCE_BOLT:
2627 wipe_engr_at(x, y, d(2,4));
2628 break;
2629 default:
2630 break;
2631 }
2632 }
2633 }
2634
2635 return disclose;
2636 }
2637
2638 /* called for various wand and spell effects - M. Stephenson */
2639 void
weffects(obj)2640 weffects(obj)
2641 register struct obj *obj;
2642 {
2643 int otyp = obj->otyp;
2644 boolean disclose = FALSE, was_unkn = !objects[otyp].oc_name_known;
2645
2646 exercise(A_WIS, TRUE);
2647 #ifdef STEED
2648 if (u.usteed && (objects[otyp].oc_dir != NODIR) &&
2649 !u.dx && !u.dy && (u.dz > 0) && zap_steed(obj)) {
2650 disclose = TRUE;
2651 } else
2652 #endif
2653 if (objects[otyp].oc_dir == IMMEDIATE) {
2654 obj_zapped = FALSE;
2655
2656 if (u.uswallow) {
2657 (void) bhitm(u.ustuck, obj);
2658 /* [how about `bhitpile(u.ustuck->minvent)' effect?] */
2659 } else if (u.dz) {
2660 disclose = zap_updown(obj);
2661 } else {
2662 (void) bhit(u.dx,u.dy, rn1(8,6),ZAPPED_WAND, bhitm,bhito, obj, NULL);
2663 }
2664 /* give a clue if obj_zapped */
2665 if (obj_zapped)
2666 You_feel("shuddering vibrations.");
2667
2668 } else if (objects[otyp].oc_dir == NODIR) {
2669 zapnodir(obj);
2670
2671 } else {
2672 /* neither immediate nor directionless */
2673
2674 if (otyp == WAN_DIGGING || otyp == SPE_DIG)
2675 zap_dig();
2676 else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH)
2677 buzz(otyp - SPE_MAGIC_MISSILE + 10,
2678 u.ulevel / 2 + 1,
2679 u.ux, u.uy, u.dx, u.dy);
2680 else if (otyp >= WAN_MAGIC_MISSILE && otyp <= WAN_LIGHTNING)
2681 buzz(otyp - WAN_MAGIC_MISSILE,
2682 (otyp == WAN_MAGIC_MISSILE) ? 2 : 6,
2683 u.ux, u.uy, u.dx, u.dy);
2684 else
2685 warning("weffects: unexpected spell or wand");
2686 disclose = TRUE;
2687 }
2688 if (disclose && was_unkn) {
2689 makeknown(otyp);
2690 more_experienced(0,0,10);
2691 }
2692 return;
2693 }
2694
2695 /*
2696 * Generate the to damage bonus for a spell. Based on the hero's intelligence
2697 */
2698 int
spell_damage_bonus()2699 spell_damage_bonus()
2700 {
2701 int tmp, intell = ACURR(A_INT);
2702
2703 /* Punish low intellegence before low level else low intellegence
2704 gets punished only when high level */
2705 if (intell < 10)
2706 tmp = -3;
2707 else if (u.ulevel < 5)
2708 tmp = 0;
2709 else if (intell < 14)
2710 tmp = 0;
2711 else if (intell <= 18)
2712 tmp = 1;
2713 else /* helm of brilliance */
2714 tmp = 2;
2715
2716 return tmp;
2717 }
2718
2719 /*
2720 * Generate the to hit bonus for a spell. Based on the hero's skill in
2721 * spell class and dexterity.
2722 */
2723 STATIC_OVL int
spell_hit_bonus(skill)2724 spell_hit_bonus(skill)
2725 int skill;
2726 {
2727 int hit_bon = 0;
2728 int dex = ACURR(A_DEX);
2729
2730 switch (P_SKILL(spell_skilltype(skill))) {
2731 case P_ISRESTRICTED:
2732 case P_UNSKILLED: hit_bon = -4; break;
2733 case P_BASIC: hit_bon = 0; break;
2734 case P_SKILLED: hit_bon = 2; break;
2735 case P_EXPERT: hit_bon = 3; break;
2736 }
2737
2738 if (dex < 4)
2739 hit_bon -= 3;
2740 else if (dex < 6)
2741 hit_bon -= 2;
2742 else if (dex < 8)
2743 hit_bon -= 1;
2744 else if (dex < 14)
2745 hit_bon -= 0; /* Will change when print stuff below removed */
2746 else
2747 hit_bon += dex - 14; /* Even increment for dextrous heroes (see weapon.c abon) */
2748
2749 return hit_bon;
2750 }
2751
2752 const char *
exclam(force)2753 exclam(force)
2754 register int force;
2755 {
2756 /* force == 0 occurs e.g. with sleep ray */
2757 /* note that large force is usual with wands so that !! would
2758 require information about hand/weapon/wand */
2759 return (const char *)((force < 0) ? "?" : (force <= 4) ? "." : "!");
2760 }
2761
2762 void
hit(str,mtmp,force)2763 hit(str,mtmp,force)
2764 register const char *str;
2765 register struct monst *mtmp;
2766 register const char *force; /* usually either "." or "!" */
2767 {
2768 if((!cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp) &&
2769 !(u.uswallow && mtmp == u.ustuck))
2770 || !flags.verbose)
2771 pline("%s %s it.", The(str), vtense(str, "hit"));
2772 else pline("%s %s %s%s", The(str), vtense(str, "hit"),
2773 mon_nam(mtmp), force);
2774 }
2775
2776 void
miss(str,mtmp)2777 miss(str,mtmp)
2778 register const char *str;
2779 register struct monst *mtmp;
2780 {
2781 pline("%s %s %s.", The(str), vtense(str, "miss"),
2782 ((cansee(bhitpos.x,bhitpos.y) || canspotmon(mtmp))
2783 && flags.verbose) ?
2784 mon_nam(mtmp) : "it");
2785 }
2786
2787 /**
2788 * Called for the following distance effects:
2789 * when a weapon is thrown (weapon == THROWN_WEAPON)
2790 * when an object is kicked (KICKED_WEAPON)
2791 * when an IMMEDIATE wand is zapped (ZAPPED_WAND)
2792 * when a light beam is flashed (FLASHED_LIGHT)
2793 * when a mirror is applied (INVIS_BEAM)
2794 * A thrown/kicked object falls down at the end of its range or when a monster
2795 * is hit. The variable 'bhitpos' is set to the final position of the weapon
2796 * thrown/zapped. The ray of a wand may affect (by calling a provided
2797 * function) several objects and monsters on its path. The return value
2798 * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer.
2799 *
2800 * Check !u.uswallow before calling bhit().
2801 * This function reveals the absence of a remembered invisible monster in
2802 * necessary cases (throwing or kicking weapons). The presence of a real
2803 * one is revealed for a weapon, but if not a weapon is left up to fhitm().
2804 */
2805 struct monst *
bhit(ddx,ddy,range,weapon,fhitm,fhito,obj,obj_destroyed)2806 bhit(ddx,ddy,range,weapon,fhitm,fhito,obj,obj_destroyed)
2807 register int ddx,ddy,range; /**< direction and range */
2808 int weapon; /**< see values in hack.h */
2809 int FDECL((*fhitm), (MONST_P, OBJ_P)), /**< fns called when mon/obj hit */
2810 FDECL((*fhito), (OBJ_P, OBJ_P));
2811 struct obj *obj; /**< object tossed/used */
2812 boolean *obj_destroyed; /**< has object been deallocated? Pointer to boolean, may be NULL */
2813 {
2814 struct monst *mtmp;
2815 uchar typ;
2816 boolean shopdoor = FALSE, point_blank = TRUE;
2817 if (obj_destroyed) { *obj_destroyed = FALSE; }
2818
2819 if (weapon == KICKED_WEAPON) {
2820 /* object starts one square in front of player */
2821 bhitpos.x = u.ux + ddx;
2822 bhitpos.y = u.uy + ddy;
2823 range--;
2824 } else {
2825 bhitpos.x = u.ux;
2826 bhitpos.y = u.uy;
2827 }
2828
2829 if (weapon == FLASHED_LIGHT) {
2830 tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam));
2831 } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM)
2832 tmp_at(DISP_FLASH, obj_to_glyph(obj));
2833
2834 while(range-- > 0) {
2835 int x,y;
2836
2837 bhitpos.x += ddx;
2838 bhitpos.y += ddy;
2839 x = bhitpos.x; y = bhitpos.y;
2840
2841 if(!isok(x, y)) {
2842 bhitpos.x -= ddx;
2843 bhitpos.y -= ddy;
2844 break;
2845 }
2846
2847 if(is_pick(obj) && inside_shop(x, y) &&
2848 (mtmp = shkcatch(obj, x, y))) {
2849 tmp_at(DISP_END, 0);
2850 return(mtmp);
2851 }
2852
2853 typ = levl[bhitpos.x][bhitpos.y].typ;
2854
2855 /* iron bars will block anything big enough */
2856 if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) &&
2857 typ == IRONBARS &&
2858 hits_bars(&obj, x - ddx, y - ddy, ddx, ddy,
2859 point_blank ? 0 : !rn2(5), 1)) {
2860 /* caveat: obj might now be null... */
2861 if (obj == NULL && obj_destroyed) { *obj_destroyed = TRUE; }
2862 bhitpos.x -= ddx;
2863 bhitpos.y -= ddy;
2864 break;
2865 }
2866
2867 if (weapon == ZAPPED_WAND && find_drawbridge(&x,&y))
2868 switch (obj->otyp) {
2869 case WAN_OPENING:
2870 case SPE_KNOCK:
2871 if (is_db_wall(bhitpos.x, bhitpos.y)) {
2872 if (cansee(x,y) || cansee(bhitpos.x,bhitpos.y))
2873 makeknown(obj->otyp);
2874 open_drawbridge(x,y);
2875 }
2876 break;
2877 case WAN_LOCKING:
2878 case SPE_WIZARD_LOCK:
2879 if ((cansee(x,y) || cansee(bhitpos.x, bhitpos.y))
2880 && levl[x][y].typ == DRAWBRIDGE_DOWN)
2881 makeknown(obj->otyp);
2882 if (!close_drawbridge(x,y)) {
2883 /* stop the ray to prevent creation of a door
2884 in the drawbridge's doorway */
2885 return (struct monst *)0;
2886 }
2887 break;
2888 case WAN_STRIKING:
2889 case SPE_FORCE_BOLT:
2890 if (typ != DRAWBRIDGE_UP)
2891 destroy_drawbridge(x,y);
2892 makeknown(obj->otyp);
2893 break;
2894 }
2895
2896 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
2897 notonhead = (bhitpos.x != mtmp->mx ||
2898 bhitpos.y != mtmp->my);
2899 if (weapon != FLASHED_LIGHT) {
2900 if(weapon != ZAPPED_WAND) {
2901 if(weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
2902 if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) {
2903 if (weapon != INVIS_BEAM) {
2904 map_invisible(bhitpos.x, bhitpos.y);
2905 return(mtmp);
2906 }
2907 } else
2908 return(mtmp);
2909 }
2910 if (weapon != INVIS_BEAM) {
2911 (*fhitm)(mtmp, obj);
2912 range -= 3;
2913 }
2914 } else {
2915 /* FLASHED_LIGHT hitting invisible monster
2916 should pass through instead of stop so
2917 we call flash_hits_mon() directly rather
2918 than returning mtmp back to caller. That
2919 allows the flash to keep on going. Note
2920 that we use mtmp->minvis not canspotmon()
2921 because it makes no difference whether
2922 the hero can see the monster or not.*/
2923 if (mtmp->minvis) {
2924 obj->ox = u.ux, obj->oy = u.uy;
2925 (void) flash_hits_mon(mtmp, obj);
2926 } else {
2927 tmp_at(DISP_END, 0);
2928 return(mtmp); /* caller will call flash_hits_mon */
2929 }
2930 }
2931 } else {
2932 if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING &&
2933 glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) {
2934 unmap_object(bhitpos.x, bhitpos.y);
2935 newsym(x, y);
2936 }
2937 }
2938 if(fhito) {
2939 if(bhitpile(obj,fhito,bhitpos.x,bhitpos.y))
2940 range--;
2941 } else {
2942 if(weapon == KICKED_WEAPON &&
2943 ((obj->oclass == COIN_CLASS &&
2944 OBJ_AT(bhitpos.x, bhitpos.y)) ||
2945 ship_object(obj, bhitpos.x, bhitpos.y,
2946 costly_spot(bhitpos.x, bhitpos.y)))) {
2947 tmp_at(DISP_END, 0);
2948 return (struct monst *)0;
2949 }
2950 }
2951 if(weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) {
2952 switch (obj->otyp) {
2953 case WAN_OPENING:
2954 case WAN_LOCKING:
2955 case WAN_STRIKING:
2956 case SPE_KNOCK:
2957 case SPE_WIZARD_LOCK:
2958 case SPE_FORCE_BOLT:
2959 if (doorlock(obj, bhitpos.x, bhitpos.y)) {
2960 if (cansee(bhitpos.x, bhitpos.y) ||
2961 (obj->otyp == WAN_STRIKING))
2962 makeknown(obj->otyp);
2963 if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN
2964 && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) {
2965 shopdoor = TRUE;
2966 add_damage(bhitpos.x, bhitpos.y, 400L);
2967 }
2968 }
2969 break;
2970 }
2971 }
2972 if(!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) {
2973 bhitpos.x -= ddx;
2974 bhitpos.y -= ddy;
2975 break;
2976 }
2977 if(weapon != ZAPPED_WAND && weapon != INVIS_BEAM) {
2978 /* 'I' present but no monster: erase */
2979 /* do this before the tmp_at() */
2980 if (glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)
2981 && cansee(x, y)) {
2982 unmap_object(bhitpos.x, bhitpos.y);
2983 newsym(x, y);
2984 }
2985 tmp_at(bhitpos.x, bhitpos.y);
2986 delay_output();
2987 /* kicked objects fall in pools */
2988 if((weapon == KICKED_WEAPON) &&
2989 (is_pool(bhitpos.x, bhitpos.y) ||
2990 is_lava(bhitpos.x, bhitpos.y)))
2991 break;
2992 #ifdef SINKS
2993 if(IS_SINK(typ) && weapon != FLASHED_LIGHT)
2994 break; /* physical objects fall onto sink */
2995 #endif
2996 }
2997 /* limit range of ball so hero won't make an invalid move */
2998 if (weapon == THROWN_WEAPON && range > 0 &&
2999 obj->otyp == HEAVY_IRON_BALL) {
3000 struct obj *bobj;
3001 struct trap *t;
3002 if ((bobj = sobj_at(BOULDER, x, y)) != 0) {
3003 if (cansee(x,y))
3004 pline("%s hits %s.",
3005 The(distant_name(obj, xname)), an(xname(bobj)));
3006 range = 0;
3007 } else if (obj == uball) {
3008 if (!test_move(x - ddx, y - ddy, ddx, ddy, TEST_MOVE)) {
3009 /* nb: it didn't hit anything directly */
3010 if (cansee(x,y))
3011 pline("%s jerks to an abrupt halt.",
3012 The(distant_name(obj, xname))); /* lame */
3013 range = 0;
3014 } else if (In_sokoban(&u.uz) && (t = t_at(x, y)) != 0 &&
3015 (t->ttyp == PIT || t->ttyp == SPIKED_PIT ||
3016 t->ttyp == HOLE || t->ttyp == TRAPDOOR)) {
3017 /* hero falls into the trap, so ball stops */
3018 range = 0;
3019 }
3020 }
3021 }
3022
3023 /* thrown/kicked missile has moved away from its starting spot */
3024 point_blank = FALSE; /* affects passing through iron bars */
3025 }
3026
3027 if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
3028
3029 if(shopdoor)
3030 pay_for_damage("destroy", FALSE);
3031
3032 return (struct monst *)0;
3033 }
3034
3035 struct monst *
boomhit(dx,dy)3036 boomhit(dx, dy)
3037 int dx, dy;
3038 {
3039 register int i, ct;
3040 int boom = S_boomleft; /* showsym[] index */
3041 struct monst *mtmp;
3042
3043 bhitpos.x = u.ux;
3044 bhitpos.y = u.uy;
3045
3046 for (i = 0; i < 8; i++) if (xdir[i] == dx && ydir[i] == dy) break;
3047 tmp_at(DISP_FLASH, cmap_to_glyph(boom));
3048 for (ct = 0; ct < 10; ct++) {
3049 if(i == 8) i = 0;
3050 boom = (boom == S_boomleft) ? S_boomright : S_boomleft;
3051 tmp_at(DISP_CHANGE, cmap_to_glyph(boom));/* change glyph */
3052 dx = xdir[i];
3053 dy = ydir[i];
3054 bhitpos.x += dx;
3055 bhitpos.y += dy;
3056 if(MON_AT(bhitpos.x, bhitpos.y)) {
3057 mtmp = m_at(bhitpos.x,bhitpos.y);
3058 m_respond(mtmp);
3059 tmp_at(DISP_END, 0);
3060 return(mtmp);
3061 }
3062 if(!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ) ||
3063 closed_door(bhitpos.x, bhitpos.y)) {
3064 bhitpos.x -= dx;
3065 bhitpos.y -= dy;
3066 break;
3067 }
3068 if(bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
3069 if(Fumbling || rn2(20) >= ACURR(A_DEX)) {
3070 /* we hit ourselves */
3071 (void) thitu(10, rnd(10), (struct obj *)0,
3072 "boomerang");
3073 break;
3074 } else { /* we catch it */
3075 tmp_at(DISP_END, 0);
3076 You("skillfully catch the boomerang.");
3077 return(&youmonst);
3078 }
3079 }
3080 tmp_at(bhitpos.x, bhitpos.y);
3081 delay_output();
3082 if(ct % 5 != 0) i++;
3083 #ifdef SINKS
3084 if(IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) {
3085 pline("Klonk!");
3086 break; /* boomerang falls on sink */
3087 }
3088 #endif
3089 }
3090 tmp_at(DISP_END, 0); /* do not leave last symbol */
3091 return (struct monst *)0;
3092 }
3093
3094 STATIC_OVL int
zhitm(mon,type,nd,ootmp)3095 zhitm(mon, type, nd, ootmp) /* returns damage to mon */
3096 register struct monst *mon;
3097 register int type, nd;
3098 struct obj **ootmp; /* to return worn armor for caller to disintegrate */
3099 {
3100 register int tmp = 0;
3101 register int abstype = abs(type) % 10;
3102 boolean sho_shieldeff = FALSE;
3103 boolean spellcaster = is_hero_spell(type); /* maybe get a bonus! */
3104
3105 *ootmp = (struct obj *)0;
3106 switch(abstype) {
3107 case ZT_MAGIC_MISSILE:
3108 if (resists_magm(mon)) {
3109 sho_shieldeff = TRUE;
3110 break;
3111 }
3112 tmp = d(nd,6);
3113 if (spellcaster)
3114 tmp += spell_damage_bonus();
3115 #ifdef WIZ_PATCH_DEBUG
3116 if (spellcaster)
3117 pline("Damage = %d + %d", tmp-spell_damage_bonus(),
3118 spell_damage_bonus());
3119 #endif
3120 break;
3121 case ZT_LAVA:
3122 case ZT_FIRE:
3123 if (resists_fire(mon)) {
3124 sho_shieldeff = TRUE;
3125 break;
3126 }
3127 tmp = d(nd,6);
3128 if (resists_cold(mon)) tmp += 7;
3129 if (spellcaster)
3130 tmp += spell_damage_bonus();
3131 #ifdef WIZ_PATCH_DEBUG
3132 if (spellcaster)
3133 pline("Damage = %d + %d",tmp-spell_damage_bonus(),
3134 spell_damage_bonus());
3135 #endif
3136 if (burnarmor(mon)) {
3137 if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_FIRE);
3138 if (!rn2(3)) (void)destroy_mitem(mon, SCROLL_CLASS, AD_FIRE);
3139 if (!rn2(5)) (void)destroy_mitem(mon, SPBOOK_CLASS, AD_FIRE);
3140 }
3141 break;
3142 case ZT_COLD:
3143 if (resists_cold(mon)) {
3144 sho_shieldeff = TRUE;
3145 break;
3146 }
3147 tmp = d(nd,6);
3148 if (resists_fire(mon)) tmp += d(nd, 3);
3149 if (spellcaster)
3150 tmp += spell_damage_bonus();
3151 #ifdef WIZ_PATCH_DEBUG
3152 if (spellcaster)
3153 pline("Damage = %d + %d", tmp-spell_damage_bonus(),
3154 spell_damage_bonus());
3155 #endif
3156 if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_COLD);
3157 break;
3158 case ZT_SLEEP:
3159 tmp = 0;
3160 (void)sleep_monst(mon, d(nd, 25),
3161 type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0');
3162 break;
3163 case ZT_DEATH: /* death/disintegration */
3164 if(abs(type) != ZT_BREATH(ZT_DEATH)) { /* death */
3165 if(mon->data == &mons[PM_DEATH]) {
3166 mon->mhpmax += mon->mhpmax/2;
3167 if (mon->mhpmax >= MAGIC_COOKIE)
3168 mon->mhpmax = MAGIC_COOKIE - 1;
3169 mon->mhp = mon->mhpmax;
3170 tmp = 0;
3171 break;
3172 }
3173 if (nonliving(mon->data) || is_demon(mon->data) ||
3174 resists_magm(mon) || mon->data->msound == MS_LEADER) { /* similar to player */
3175 sho_shieldeff = TRUE;
3176 break;
3177 }
3178 type = -1; /* so they don't get saving throws */
3179 } else {
3180 struct obj *otmp2;
3181
3182 if (resists_disint(mon)) {
3183 sho_shieldeff = TRUE;
3184 } else if (mon->misc_worn_check & W_ARMS) {
3185 /* destroy shield; victim survives */
3186 *ootmp = which_armor(mon, W_ARMS);
3187 } else if (mon->misc_worn_check & W_ARM) {
3188 /* destroy body armor, also cloak if present */
3189 *ootmp = which_armor(mon, W_ARM);
3190 if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
3191 m_useup(mon, otmp2);
3192 } else {
3193 /* no body armor, victim dies; destroy cloak
3194 and shirt now in case target gets life-saved */
3195 tmp = MAGIC_COOKIE;
3196 if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
3197 m_useup(mon, otmp2);
3198 #ifdef TOURIST
3199 if ((otmp2 = which_armor(mon, W_ARMU)) != 0)
3200 m_useup(mon, otmp2);
3201 #endif
3202 }
3203 type = -1; /* no saving throw wanted */
3204 break; /* not ordinary damage */
3205 }
3206 tmp = mon->mhp+1;
3207 break;
3208 case ZT_LIGHTNING:
3209 if (resists_elec(mon)) {
3210 sho_shieldeff = TRUE;
3211 tmp = 0;
3212 /* can still blind the monster */
3213 } else
3214 tmp = d(nd,6);
3215 if (spellcaster)
3216 tmp += spell_damage_bonus();
3217 #ifdef WIZ_PATCH_DEBUG
3218 if (spellcaster)
3219 pline("Damage = %d + %d", tmp-spell_damage_bonus(),
3220 spell_damage_bonus());
3221 #endif
3222 if (!resists_blnd(mon) &&
3223 !(type > 0 && u.uswallow && mon == u.ustuck)) {
3224 register unsigned rnd_tmp = rnd(50);
3225 mon->mcansee = 0;
3226 if((mon->mblinded + rnd_tmp) > 127)
3227 mon->mblinded = 127;
3228 else mon->mblinded += rnd_tmp;
3229 }
3230 if (!rn2(3)) (void)destroy_mitem(mon, WAND_CLASS, AD_ELEC);
3231 /* not actually possible yet */
3232 if (!rn2(3)) (void)destroy_mitem(mon, RING_CLASS, AD_ELEC);
3233 break;
3234 case ZT_POISON_GAS:
3235 if (resists_poison(mon)) {
3236 sho_shieldeff = TRUE;
3237 break;
3238 }
3239 tmp = d(nd,6);
3240 break;
3241 case ZT_ACID:
3242 if (resists_acid(mon)) {
3243 sho_shieldeff = TRUE;
3244 break;
3245 }
3246 tmp = d(nd,6);
3247 if (!rn2(6)) erode_obj(MON_WEP(mon), TRUE, TRUE);
3248 if (!rn2(6)) erode_armor(mon, TRUE);
3249 break;
3250 }
3251 if (sho_shieldeff) shieldeff(mon->mx, mon->my);
3252 if (is_hero_spell(type) && (Role_if(PM_KNIGHT) && u.uhave.questart))
3253 tmp *= 2;
3254 if (tmp > 0 && type >= 0 &&
3255 resist(mon, type < ZT_SPELL(0) ? WAND_CLASS : '\0', 0, NOTELL))
3256 tmp /= 2;
3257 if (tmp < 0) tmp = 0; /* don't allow negative damage */
3258 #ifdef WIZ_PATCH_DEBUG
3259 pline("zapped monster hp = %d (= %d - %d)", mon->mhp-tmp,mon->mhp,tmp);
3260 #endif
3261 mon->mhp -= tmp;
3262 return(tmp);
3263 }
3264
3265 STATIC_OVL void
zhitu(type,nd,fltxt,sx,sy)3266 zhitu(type, nd, fltxt, sx, sy)
3267 int type, nd;
3268 const char *fltxt;
3269 xchar sx, sy;
3270 {
3271 int dam = 0;
3272
3273 switch (abs(type) % 10) {
3274 case ZT_MAGIC_MISSILE:
3275 if (Antimagic) {
3276 shieldeff(sx, sy);
3277 pline_The("missiles bounce off!");
3278 } else {
3279 dam = d(nd,6);
3280 exercise(A_STR, FALSE);
3281 }
3282 break;
3283 case ZT_LAVA:
3284 case ZT_FIRE:
3285 if (Fire_resistance) {
3286 shieldeff(sx, sy);
3287 You("don't feel hot!");
3288 ugolemeffects(AD_FIRE, d(nd, 6));
3289 } else {
3290 dam = d(nd, 6);
3291 }
3292 burn_away_slime();
3293 if (burnarmor(&youmonst)) { /* "body hit" */
3294 if (!rn2(3)) destroy_item(POTION_CLASS, AD_FIRE);
3295 if (!rn2(3)) destroy_item(SCROLL_CLASS, AD_FIRE);
3296 if (!rn2(5)) destroy_item(SPBOOK_CLASS, AD_FIRE);
3297 }
3298 break;
3299 case ZT_COLD:
3300 if (Cold_resistance) {
3301 shieldeff(sx, sy);
3302 You("don't feel cold.");
3303 ugolemeffects(AD_COLD, d(nd, 6));
3304 } else {
3305 dam = d(nd, 6);
3306 }
3307 if (!rn2(3)) destroy_item(POTION_CLASS, AD_COLD);
3308 break;
3309 case ZT_SLEEP:
3310 if (Sleep_resistance) {
3311 shieldeff(u.ux, u.uy);
3312 You("don't feel sleepy.");
3313 } else {
3314 fall_asleep(-d(nd,25), TRUE); /* sleep ray */
3315 }
3316 break;
3317 case ZT_DEATH:
3318 if (abs(type) == ZT_BREATH(ZT_DEATH)) {
3319 if (Disint_resistance) {
3320 You("are not disintegrated.");
3321 break;
3322 } else if (uarms) {
3323 /* destroy shield; other possessions are safe */
3324 (void) destroy_arm(uarms);
3325 break;
3326 } else if (uarm) {
3327 /* destroy suit; if present, cloak goes too */
3328 if (uarmc) (void) destroy_arm(uarmc);
3329 (void) destroy_arm(uarm);
3330 break;
3331 }
3332 /* no shield or suit, you're dead; wipe out cloak
3333 and/or shirt in case of life-saving or bones */
3334 if (uarmc) (void) destroy_arm(uarmc);
3335 #ifdef TOURIST
3336 if (uarmu) (void) destroy_arm(uarmu);
3337 #endif
3338 } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
3339 shieldeff(sx, sy);
3340 You("seem unaffected.");
3341 break;
3342 } else if (Antimagic) {
3343 shieldeff(sx, sy);
3344 You("aren't affected.");
3345 break;
3346 }
3347 killer_format = KILLED_BY_AN;
3348 killer = fltxt;
3349 /* when killed by disintegration breath, don't leave corpse */
3350 u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM;
3351 #ifdef WEBB_DISINT
3352 done((type== -ZT_BREATH(ZT_DEATH)) ? DISINTEGRATED : DIED);
3353 #else
3354 done(DIED);
3355 #endif
3356 return; /* lifesaved */
3357 case ZT_LIGHTNING:
3358 if (Shock_resistance) {
3359 shieldeff(sx, sy);
3360 You("aren't affected.");
3361 ugolemeffects(AD_ELEC, d(nd, 6));
3362 } else {
3363 dam = d(nd, 6);
3364 exercise(A_CON, FALSE);
3365 }
3366 if (!rn2(3)) destroy_item(WAND_CLASS, AD_ELEC);
3367 if (!rn2(3)) destroy_item(RING_CLASS, AD_ELEC);
3368 break;
3369 case ZT_POISON_GAS:
3370 poisoned("blast", A_DEX, "poisoned blast", 15);
3371 break;
3372 case ZT_ACID:
3373 if (Acid_resistance) {
3374 dam = 0;
3375 } else {
3376 pline_The("acid burns!");
3377 dam = d(nd,6);
3378 exercise(A_STR, FALSE);
3379 }
3380 /* using two weapons at once makes both of them more vulnerable */
3381 if (!rn2(u.twoweap ? 3 : 6)) erode_obj(uwep, TRUE, TRUE);
3382 if (u.twoweap && !rn2(3)) erode_obj(uswapwep, TRUE, TRUE);
3383 if (!rn2(6)) erode_armor(&youmonst, TRUE);
3384 break;
3385 }
3386
3387 if (Half_spell_damage && dam &&
3388 type < 0 && (type > -20 || type < -29)) /* !Breath */
3389 dam = (dam + 1) / 2;
3390 losehp(dam, fltxt, KILLED_BY_AN);
3391 return;
3392 }
3393
3394 void
melt_icewall(x,y)3395 melt_icewall(x, y)
3396 xchar x, y;
3397 {
3398 struct rm *lev = &levl[x][y];
3399 if (cansee(x, y)) {
3400 if (IS_CRYSTALICEWALL(lev->typ))
3401 Norep("The crystal ice wall melts and breaks down.");
3402 else
3403 Norep("The ice wall melts away.");
3404 }
3405 lev->typ = ICE;
3406 newsym(x,y);
3407 unblock_point(x,y);
3408 vision_recalc(1);
3409 }
3410
3411 void
melt_ice(x,y)3412 melt_ice(x, y)
3413 xchar x, y;
3414 {
3415 struct rm *lev = &levl[x][y];
3416 struct obj *otmp;
3417
3418 if (lev->typ == DRAWBRIDGE_UP) {
3419 lev->drawbridgemask &= ~DB_UNDER;
3420 lev->drawbridgemask |= DB_MOAT; /* revert to DB_MOAT */
3421 } else { /* lev->typ == ICE */
3422 lev->typ = (lev->icedpool == ICED_POOL ? POOL :
3423 lev->icedpool == ICED_BOG ? BOG : MOAT);
3424 lev->icedpool = 0;
3425 }
3426 obj_ice_effects(x, y, FALSE);
3427 unearth_objs(x, y);
3428 if (Underwater) vision_recalc(1);
3429 newsym(x,y);
3430 if (cansee(x,y)) Norep("The ice crackles and melts.");
3431 if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
3432 if (cansee(x,y)) pline("%s settles...", An(xname(otmp)));
3433 do {
3434 obj_extract_self(otmp); /* boulder isn't being pushed */
3435 if (!boulder_hits_pool(otmp, x, y, FALSE))
3436 warning("melt_ice: no pool?");
3437 /* try again if there's another boulder and pool didn't fill */
3438 } while ((is_pool(x,y) || is_swamp(x,y)) && (otmp = sobj_at(BOULDER, x, y)) != 0);
3439 newsym(x,y);
3440 }
3441 if (x == u.ux && y == u.uy)
3442 spoteffects(TRUE); /* possibly drown, notice objects */
3443 }
3444
3445 /*
3446 * burn scrolls and spellbooks on floor at position x,y
3447 * return the number of scrolls and spellbooks burned
3448 */
3449 int
burn_floor_paper(x,y,give_feedback,u_caused)3450 burn_floor_paper(x, y, give_feedback, u_caused)
3451 int x, y;
3452 boolean give_feedback; /* caller needs to decide about visibility checks */
3453 boolean u_caused;
3454 {
3455 struct obj *obj, *obj2;
3456 long i, scrquan, delquan;
3457 char buf1[BUFSZ], buf2[BUFSZ];
3458 int cnt = 0;
3459
3460 for (obj = level.objects[x][y]; obj; obj = obj2) {
3461 obj2 = obj->nexthere;
3462 if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) {
3463 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL ||
3464 obj_resists(obj, 2, 100))
3465 continue;
3466 scrquan = obj->quan; /* number present */
3467 delquan = 0; /* number to destroy */
3468 for (i = scrquan; i > 0; i--)
3469 if (!rn2(3)) delquan++;
3470 if (delquan) {
3471 /* save name before potential delobj() */
3472 if (give_feedback) {
3473 obj->quan = 1;
3474 Strcpy(buf1, (x == u.ux && y == u.uy) ?
3475 xname(obj) : distant_name(obj, xname));
3476 obj->quan = 2;
3477 Strcpy(buf2, (x == u.ux && y == u.uy) ?
3478 xname(obj) : distant_name(obj, xname));
3479 obj->quan = scrquan;
3480 }
3481 /* useupf(), which charges, only if hero caused damage */
3482 if (u_caused) useupf(obj, delquan);
3483 else if (delquan < scrquan) obj->quan -= delquan;
3484 else delobj(obj);
3485 cnt += delquan;
3486 if (give_feedback) {
3487 if (delquan > 1)
3488 pline("%ld %s burn.", delquan, buf2);
3489 else
3490 pline("%s burns.", An(buf1));
3491 }
3492 }
3493 }
3494 }
3495 return cnt;
3496 }
3497
3498 /* will zap/spell/breath attack score a hit against armor class `ac'? */
3499 STATIC_OVL int
zap_hit(ac,type)3500 zap_hit(ac, type)
3501 int ac;
3502 int type; /* either hero cast spell type or 0 */
3503 {
3504 int chance = rn2(20);
3505 int spell_bonus = type ? spell_hit_bonus(type) : 0;
3506
3507 /* small chance for naked target to avoid being hit */
3508 if (!chance) return rnd(10) < ac+spell_bonus;
3509
3510 /* very high armor protection does not achieve invulnerability */
3511 ac = AC_VALUE(ac);
3512
3513 return (3 - chance) < ac+spell_bonus;
3514 }
3515
3516 /* type == 0 to 9 : you shooting a wand */
3517 /* type == 10 to 19 : you casting a spell */
3518 /* type == 20 to 29 : you breathing as a monster */
3519 /* type == -10 to -19 : monster casting spell */
3520 /* type == -20 to -29 : monster breathing at you */
3521 /* type == -30 to -39 : monster shooting a wand */
3522 /* called with dx = dy = 0 with vertical bolts */
3523 void
buzz(type,nd,sx,sy,dx,dy)3524 buzz(type,nd,sx,sy,dx,dy)
3525 register int type, nd;
3526 register xchar sx,sy;
3527 register int dx,dy;
3528 {
3529 int range, abstype = abs(type) % 10;
3530 struct rm *lev;
3531 register xchar lsx, lsy;
3532 struct monst *mon;
3533 coord save_bhitpos;
3534 boolean shopdamage = FALSE;
3535 register const char *fltxt;
3536 struct obj *otmp;
3537 int spell_type;
3538
3539 /* if its a Hero Spell then get its SPE_TYPE */
3540 spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0;
3541
3542 fltxt = flash_types[(type <= -30) ? abstype : abs(type)];
3543 if(u.uswallow) {
3544 register int tmp;
3545
3546 if(type < 0) return;
3547 tmp = zhitm(u.ustuck, type, nd, &otmp);
3548 if(!u.ustuck) u.uswallow = 0;
3549 else pline("%s rips into %s%s",
3550 The(fltxt), mon_nam(u.ustuck), exclam(tmp));
3551 /* Using disintegration from the inside only makes a hole... */
3552 if (tmp == MAGIC_COOKIE)
3553 u.ustuck->mhp = 0;
3554 if (u.ustuck->mhp < 1)
3555 killed(u.ustuck);
3556 else
3557 showdmg(tmp, FALSE);
3558 return;
3559 }
3560 if(type < 0) newsym(u.ux,u.uy);
3561 range = rn1(7,7);
3562 if(dx == 0 && dy == 0) range = 1;
3563 save_bhitpos = bhitpos;
3564
3565 tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype));
3566 while(range-- > 0) {
3567 lsx = sx; sx += dx;
3568 lsy = sy; sy += dy;
3569 if(isok(sx,sy) && (lev = &levl[sx][sy])->typ) {
3570 mon = m_at(sx, sy);
3571 if(cansee(sx,sy)) {
3572 /* reveal/unreveal invisible monsters before tmp_at() */
3573 if (mon && !canspotmon(mon))
3574 map_invisible(sx, sy);
3575 else if (!mon && glyph_is_invisible(levl[sx][sy].glyph)) {
3576 unmap_object(sx, sy);
3577 newsym(sx, sy);
3578 }
3579 if(ZAP_POS(lev->typ) || (isok(lsx,lsy) && cansee(lsx,lsy)))
3580 tmp_at(sx,sy);
3581 delay_output(); /* wait a little */
3582 }
3583 } else
3584 goto make_bounce;
3585
3586 /* hit() and miss() need bhitpos to match the target */
3587 bhitpos.x = sx, bhitpos.y = sy;
3588 /* Fireballs only damage when they explode */
3589 if (type != ZT_SPELL(ZT_FIRE))
3590 range += zap_over_floor(sx, sy, type, &shopdamage);
3591
3592 if (mon) {
3593 if (type == ZT_SPELL(ZT_FIRE)) break;
3594 if (type >= 0) mon->mstrategy &= ~STRAT_WAITMASK;
3595 #ifdef STEED
3596 buzzmonst:
3597 #endif
3598 if (zap_hit(find_mac(mon), spell_type)) {
3599 if (mon_reflects(mon, (char *)0)) {
3600 if(cansee(mon->mx,mon->my)) {
3601 hit(fltxt, mon, exclam(0));
3602 shieldeff(mon->mx, mon->my);
3603 (void) mon_reflects(mon, "But it reflects from %s %s!");
3604 }
3605 /* lava is reflected, but doesn't bounce back */
3606 if (abstype == ZT_LAVA)
3607 range = 0;
3608 dx = -dx;
3609 dy = -dy;
3610 } else {
3611 boolean mon_could_move = mon->mcanmove;
3612 int tmp = zhitm(mon, type, nd, &otmp);
3613
3614 if (is_rider(mon->data) && abs(type) == ZT_BREATH(ZT_DEATH)) {
3615 if (canseemon(mon)) {
3616 hit(fltxt, mon, ".");
3617 pline("%s disintegrates.", Monnam(mon));
3618 pline("%s body reintegrates before your %s!",
3619 s_suffix(Monnam(mon)),
3620 (eyecount(youmonst.data) == 1) ?
3621 body_part(EYE) : makeplural(body_part(EYE)));
3622 pline("%s resurrects!", Monnam(mon));
3623 }
3624 mon->mhp = mon->mhpmax;
3625 break; /* Out of while loop */
3626 }
3627 if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) {
3628 if (canseemon(mon)) {
3629 hit(fltxt, mon, ".");
3630 pline("%s absorbs the deadly %s!", Monnam(mon),
3631 type == ZT_BREATH(ZT_DEATH) ?
3632 "blast" : "ray");
3633 pline("It seems even stronger than before.");
3634 }
3635 break; /* Out of while loop */
3636 }
3637
3638 if (tmp == MAGIC_COOKIE) { /* disintegration */
3639 struct obj *otmp2, *m_amulet = mlifesaver(mon);
3640
3641 if (canseemon(mon)) {
3642 if (!m_amulet)
3643 pline("%s is disintegrated!", Monnam(mon));
3644 else
3645 hit(fltxt, mon, "!");
3646 }
3647 #ifndef GOLDOBJ
3648 mon->mgold = 0L;
3649 #endif
3650
3651 /* note: worn amulet of life saving must be preserved in order to operate */
3652 #ifndef oresist_disintegration
3653 #define oresist_disintegration(obj) \
3654 (objects[obj->otyp].oc_oprop == DISINT_RES || \
3655 obj_resists(obj, 5, 50) || is_quest_artifact(obj) || \
3656 obj == m_amulet)
3657 #endif
3658 for (otmp = mon->minvent; otmp; otmp = otmp2) {
3659 otmp2 = otmp->nobj;
3660 if (
3661 #ifdef WEBB_DISINT
3662 otmp == m_amulet ||
3663 #endif
3664 !oresist_disintegration(otmp)) {
3665 obj_extract_self(otmp);
3666 obfree(otmp, (struct obj *)0);
3667 }
3668 }
3669
3670 if (type < 0)
3671 monkilled(mon, (char *)0, -AD_RBRE);
3672 else
3673 xkilled(mon, 2);
3674 } else if(mon->mhp < 1) {
3675 if(type < 0)
3676 monkilled(mon, fltxt, AD_RBRE);
3677 else
3678 killed(mon);
3679 } else {
3680 if (!otmp) {
3681 /* normal non-fatal hit */
3682 hit(fltxt, mon, exclam(tmp));
3683 if (Role_if(PM_HEALER) && flags.wounds) wounds_message(mon);
3684 } else {
3685 /* some armor was destroyed; no damage done */
3686 if (canseemon(mon))
3687 pline("%s %s is disintegrated!",
3688 s_suffix(Monnam(mon)),
3689 distant_name(otmp, xname));
3690 m_useup(mon, otmp);
3691 }
3692 if (mon_could_move && !mon->mcanmove) /* ZT_SLEEP */
3693 slept_monst(mon);
3694 }
3695 if (mon->mhp > 0) showdmg(tmp, FALSE);
3696 }
3697 range -= 2;
3698 } else {
3699 miss(fltxt,mon);
3700 }
3701 } else if (sx == u.ux && sy == u.uy && range >= 0) {
3702 nomul(0, 0);
3703 #ifdef STEED
3704 if (u.usteed && !rn2(3) && !mon_reflects(u.usteed, (char *)0)) {
3705 mon = u.usteed;
3706 goto buzzmonst;
3707 } else
3708 #endif
3709 if (zap_hit((int) u.uac, 0)) {
3710 range -= 2;
3711 pline("%s hits you!", The(fltxt));
3712 if (Reflecting) {
3713 if (!Blind) {
3714 (void) ureflects("But %s reflects from your %s!", "it");
3715 } else
3716 pline("For some reason you are not affected.");
3717 dx = -dx;
3718 dy = -dy;
3719 /* lava is reflected, but doesn't bounce back */
3720 if (abstype == ZT_LAVA)
3721 range = 0;
3722 shieldeff(sx, sy);
3723 } else {
3724 zhitu(type, nd, fltxt, sx, sy);
3725 }
3726 } else {
3727 pline("%s whizzes by you!", The(fltxt));
3728 }
3729 if (abstype == ZT_LIGHTNING && !resists_blnd(&youmonst)) {
3730 You(are_blinded_by_the_flash);
3731 make_blinded((long)d(nd,50),FALSE);
3732 if (!Blind) Your("%s", vision_clears);
3733 }
3734 stop_occupation();
3735 nomul(0, 0);
3736 }
3737
3738 if(lev->typ == TREE && abstype == ZT_DEATH && abs(type) != ZT_BREATH(ZT_DEATH)) {
3739 lev->typ = DEADTREE;
3740 if (cansee(sx,sy)) {
3741 pline("The tree withers!");
3742 newsym(sx,sy);
3743 }
3744 range = 0;
3745 break;
3746 }
3747
3748 if(!ZAP_POS(lev->typ) || (closed_door(sx, sy) && (range >= 0))) {
3749 int bounce;
3750 uchar rmn;
3751
3752 make_bounce:
3753 if (type == ZT_SPELL(ZT_FIRE)) {
3754 sx = lsx;
3755 sy = lsy;
3756 break; /* fireballs explode before the wall */
3757 }
3758 bounce = 0;
3759 range--;
3760 if (range) {
3761 /* lava does not bounce off walls, but melts them;
3762 intentionally do not use isok() here so lava
3763 will not bounce off of the edge of the map */
3764 if (abstype == ZT_LAVA) {
3765 if (IS_STWALL(levl[sx][sy].typ) &&
3766 !(levl[sx][sy].wall_info & W_NONDIGGABLE)) {
3767 levl[sx][sy].typ = LAVAPOOL;
3768 if (cansee(sx, sy)) {
3769 pline("%s melts the wall!", The(fltxt));
3770 newsym(sx, sy);
3771 }
3772 } else if (is_any_icewall(sx, sy)) {
3773 melt_icewall(sx, sy);
3774 }
3775 break;
3776 } else {
3777 if (isok(lsx, lsy) && cansee(lsx, lsy))
3778 pline("%s bounces!", The(fltxt));
3779 }
3780 }
3781 if(!dx || !dy || !rn2(20)) {
3782 dx = -dx;
3783 dy = -dy;
3784 } else {
3785 if(isok(sx,lsy) && ZAP_POS(rmn = levl[sx][lsy].typ) &&
3786 !closed_door(sx,lsy) &&
3787 (IS_ROOM(rmn) || (isok(sx+dx,lsy) &&
3788 ZAP_POS(levl[sx+dx][lsy].typ))))
3789 bounce = 1;
3790 if(isok(lsx,sy) && ZAP_POS(rmn = levl[lsx][sy].typ) &&
3791 !closed_door(lsx,sy) &&
3792 (IS_ROOM(rmn) || (isok(lsx,sy+dy) &&
3793 ZAP_POS(levl[lsx][sy+dy].typ))))
3794 if(!bounce || rn2(2))
3795 bounce = 2;
3796
3797 switch(bounce) {
3798 case 0: dx = -dx; /* fall into... */
3799 case 1: dy = -dy; break;
3800 case 2: dx = -dx; break;
3801 }
3802 tmp_at(DISP_CHANGE, zapdir_to_glyph(dx,dy,abstype));
3803 }
3804 }
3805 }
3806 tmp_at(DISP_END,0);
3807 if (type == ZT_SPELL(ZT_FIRE))
3808 explode(sx, sy, type, d(12,6), 0, EXPL_FIERY);
3809 if (shopdamage)
3810 pay_for_damage(abstype == ZT_FIRE ? "burn away" :
3811 abstype == ZT_COLD ? "shatter" :
3812 abstype == ZT_DEATH ? "disintegrate" : "destroy", FALSE);
3813 bhitpos = save_bhitpos;
3814 }
3815
3816 /* Burn floor scrolls, evaporate pools, etc... in a single square. Used
3817 * both for normal bolts of fire, cold, etc... and for fireballs.
3818 * Sets shopdamage to TRUE if a shop door is destroyed, and returns the
3819 * amount by which range is reduced (the latter is just ignored by fireballs)
3820 */
3821 int
zap_over_floor(x,y,type,shopdamage)3822 zap_over_floor(x, y, type, shopdamage)
3823 xchar x, y;
3824 int type;
3825 boolean *shopdamage;
3826 {
3827 struct monst *mon;
3828 int abstype = abs(type) % 10;
3829 struct rm *lev = &levl[x][y];
3830 int rangemod = 0;
3831
3832 if(abstype == ZT_FIRE) {
3833 struct trap *t = t_at(x, y);
3834
3835 if (x == u.ux && y == u.uy && u.ufeetfrozen) {
3836 u.ufeetfrozen = 0;
3837 The("fire melts the ice holding you in place.");
3838 }
3839
3840 if (t && t->ttyp == WEB) {
3841 /* a burning web is too flimsy to notice if you can't see it */
3842 if (cansee(x,y)) Norep("A web bursts into flames!");
3843 (void) delfloortrap(t);
3844 if (cansee(x,y)) newsym(x,y);
3845 }
3846 if(is_any_icewall(x, y)) {
3847 melt_icewall(x, y);
3848 } else if(is_ice(x, y)) {
3849 melt_ice(x, y);
3850 } else if(is_pool(x,y) || is_swamp(x,y)) {
3851 const char *msgtxt = "You hear hissing gas.";
3852 schar filltyp;
3853 int dried = 0;
3854 if(lev->typ != POOL && lev->typ != BOG) { /* MOAT or DRAWBRIDGE_UP */
3855 if (cansee(x,y)) msgtxt = "Some water evaporates.";
3856 } else {
3857 register struct trap *ttmp;
3858
3859 rangemod -= 3;
3860 if (lev->typ == BOG) {
3861 lev->typ = ROOM;
3862 filltyp = fillholetyp(x,y);
3863 if (filltyp == ROOM) {
3864 dried = 1;
3865 } else {
3866 lev->typ = BOG;
3867 }
3868 } else {
3869 lev->typ = ROOM;
3870 filltyp = fillholetyp(x,y);
3871 if (filltyp == ROOM) {
3872 ttmp = maketrap(x, y, PIT);
3873 if (ttmp) ttmp->tseen = 1;
3874 dried = 1;
3875 } else {
3876 lev->typ = filltyp;
3877 }
3878 }
3879 if (cansee(x,y))
3880 msgtxt = (dried) ? "The water evaporates." :
3881 "Some water evaporates.";
3882 }
3883 Norep("%s", msgtxt);
3884 if (dried) newsym(x,y);
3885 } else if(IS_FOUNTAIN(lev->typ)) {
3886 if (cansee(x,y))
3887 pline("Steam billows from the fountain.");
3888 rangemod -= 1;
3889 dryup(x, y, type > 0);
3890 }
3891 }
3892 else if(abstype == ZT_COLD && (is_pool(x,y) || is_lava(x,y) || is_swamp(x,y))) {
3893 boolean lava = is_lava(x,y);
3894 boolean swamp = is_swamp(x,y);
3895 boolean moat = (!lava && !swamp && (lev->typ != POOL) &&
3896 (lev->typ != WATER) &&
3897 !Is_medusa_level(&u.uz) &&
3898 !Is_waterlevel(&u.uz));
3899
3900 if (lev->typ == WATER) {
3901 /* For now, don't let WATER freeze. */
3902 if (cansee(x,y))
3903 pline_The("water freezes for a moment.");
3904 else
3905 You_hear("a soft crackling.");
3906 rangemod -= 1000; /* stop */
3907 } else {
3908 rangemod -= 3;
3909 if (lev->typ == DRAWBRIDGE_UP) {
3910 lev->drawbridgemask &= ~DB_UNDER; /* clear lava */
3911 lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE);
3912 } else {
3913 if (!lava)
3914 lev->icedpool =
3915 (lev->typ == POOL ? ICED_POOL :
3916 lev->typ == BOG ? ICED_BOG : ICED_MOAT);
3917 lev->typ = (lava ? ROOM : ICE);
3918 }
3919 bury_objs(x,y);
3920 if(cansee(x,y)) {
3921 if(moat)
3922 Norep("The moat is bridged with ice!");
3923 else if(lava)
3924 Norep("The lava cools and solidifies.");
3925 else
3926 Norep("The water freezes.");
3927 newsym(x,y);
3928 } else if(flags.soundok && !lava)
3929 You_hear("a crackling sound.");
3930
3931 if (x == u.ux && y == u.uy) {
3932 if (u.uinwater) { /* not just `if (Underwater)' */
3933 /* leave the no longer existent water */
3934 u.uinwater = 0;
3935 u.uundetected = 0;
3936 docrt();
3937 vision_full_recalc = 1;
3938 } else if (u.utrap && u.utraptype == TT_LAVA) {
3939 if (Passes_walls) {
3940 You("pass through the now-solid rock.");
3941 } else {
3942 u.utrap = rn1(50,20);
3943 u.utraptype = TT_INFLOOR;
3944 You("are firmly stuck in the cooling rock.");
3945 }
3946 }
3947 } else if ((mon = m_at(x,y)) != 0) {
3948 /* probably ought to do some hefty damage to any
3949 non-ice creature caught in freezing water;
3950 at a minimum, eels are forced out of hiding */
3951 if (is_swimmer(mon->data) && mon->mundetected) {
3952 mon->mundetected = 0;
3953 newsym(x,y);
3954 }
3955 }
3956 }
3957 obj_ice_effects(x,y,TRUE);
3958 }
3959 else if (abstype == ZT_POISON_GAS) {
3960 (void) create_gas_cloud(x, y, 1, 8, rn1(20, 5));
3961 }
3962 else if (abstype == ZT_ACID && levl[x][y].typ == IRONBARS && !rn2(5)) {
3963 if (cansee(x, y))
3964 pline_The("iron bars are dissolved!");
3965 else
3966 You_hear(Hallucination ? "angry snakes!" : "a hissing noise.");
3967 dissolve_bars(x, y);
3968 if (In_sokoban(&u.uz))
3969 sokoban_trickster();
3970 }
3971 if(closed_door(x, y)) {
3972 int new_doormask = -1;
3973 const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0;
3974 rangemod = -1000;
3975 /* ALI - Artifact doors */
3976 if (artifact_door(x, y))
3977 goto def_case;
3978 switch(abstype) {
3979 case ZT_LAVA:
3980 case ZT_FIRE:
3981 new_doormask = D_NODOOR;
3982 see_txt = "The door is consumed in flames!";
3983 sense_txt = "smell smoke.";
3984 break;
3985 case ZT_COLD:
3986 new_doormask = D_NODOOR;
3987 see_txt = "The door freezes and shatters!";
3988 sense_txt = "feel cold.";
3989 break;
3990 case ZT_DEATH:
3991 /* death spells/wands don't disintegrate */
3992 if(abs(type) != ZT_BREATH(ZT_DEATH))
3993 goto def_case;
3994 new_doormask = D_NODOOR;
3995 see_txt = "The door disintegrates!";
3996 hear_txt = "crashing wood.";
3997 break;
3998 case ZT_LIGHTNING:
3999 new_doormask = D_BROKEN;
4000 see_txt = "The door splinters!";
4001 hear_txt = "crackling.";
4002 break;
4003 default:
4004 def_case:
4005 if(cansee(x,y)) {
4006 pline_The("door absorbs %s %s!",
4007 (type < 0) ? "the" : "your",
4008 abs(type) < ZT_SPELL(0) ? "bolt" :
4009 abs(type) < ZT_BREATH(0) ? "spell" :
4010 "blast");
4011 } else You_feel("vibrations.");
4012 break;
4013 }
4014 if (new_doormask >= 0) { /* door gets broken */
4015 if (*in_rooms(x, y, SHOPBASE)) {
4016 if (type >= 0) {
4017 add_damage(x, y, 400L);
4018 *shopdamage = TRUE;
4019 } else /* caused by monster */
4020 add_damage(x, y, 0L);
4021 }
4022 lev->doormask = new_doormask;
4023 unblock_point(x, y); /* vision */
4024 if (cansee(x, y)) {
4025 pline("%s", see_txt);
4026 newsym(x, y);
4027 } else if (sense_txt) {
4028 You("%s", sense_txt);
4029 } else if (hear_txt) {
4030 if (flags.soundok) You_hear("%s", hear_txt);
4031 }
4032 if (picking_at(x, y)) {
4033 stop_occupation();
4034 reset_pick();
4035 }
4036 }
4037 }
4038
4039 if(OBJ_AT(x, y) && abstype == ZT_FIRE)
4040 if (burn_floor_paper(x, y, FALSE, type > 0) && couldsee(x, y)) {
4041 newsym(x,y);
4042 You("%s of smoke.",
4043 !Blind ? "see a puff" : "smell a whiff");
4044 }
4045 if ((mon = m_at(x,y)) != 0) {
4046 /* Cannot use wakeup() which also angers the monster */
4047 mon->msleeping = 0;
4048 if(mon->m_ap_type) seemimic(mon);
4049 if(type >= 0) {
4050 setmangry(mon);
4051 if(mon->ispriest && *in_rooms(mon->mx, mon->my, TEMPLE))
4052 ghod_hitsu(mon);
4053 if(mon->isshk && !*u.ushops)
4054 hot_pursuit(mon);
4055 }
4056 }
4057 return rangemod;
4058 }
4059
4060 void
fracture_rock(obj)4061 fracture_rock(obj) /* fractured by pick-axe or wand of striking */
4062 register struct obj *obj; /* no texts here! */
4063 {
4064 /* A little Sokoban guilt... */
4065 if (obj->otyp == BOULDER && In_sokoban(&u.uz) && !flags.mon_moving)
4066 sokoban_trickster();
4067
4068 obj->otyp = ROCK;
4069 obj->quan = (long) rn1(60, 7);
4070 obj->owt = weight(obj);
4071 obj->oclass = GEM_CLASS;
4072 obj->known = FALSE;
4073 obj->onamelth = 0; /* no names */
4074 obj->oxlth = 0; /* no extra data */
4075 obj->oattached = OATTACHED_NOTHING;
4076 if (obj->where == OBJ_FLOOR) {
4077 obj_extract_self(obj); /* move rocks back on top */
4078 place_object(obj, obj->ox, obj->oy);
4079 if(!does_block(obj->ox,obj->oy,&levl[obj->ox][obj->oy]))
4080 unblock_point(obj->ox,obj->oy);
4081 if(cansee(obj->ox,obj->oy))
4082 newsym(obj->ox,obj->oy);
4083 }
4084 }
4085
4086 /* handle statue hit by striking/force bolt/pick-axe */
4087 boolean
break_statue(obj)4088 break_statue(obj)
4089 register struct obj *obj;
4090 {
4091 /* [obj is assumed to be on floor, so no get_obj_location() needed] */
4092 struct trap *trap = t_at(obj->ox, obj->oy);
4093 struct obj *item;
4094
4095 if (trap && trap->ttyp == STATUE_TRAP &&
4096 activate_statue_trap(trap, obj->ox, obj->oy, TRUE))
4097 return FALSE;
4098 /* drop any objects contained inside the statue */
4099 while ((item = obj->cobj) != 0) {
4100 obj_extract_self(item);
4101 place_object(item, obj->ox, obj->oy);
4102 }
4103 if (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (obj->spe & STATUE_HISTORIC)) {
4104 You_feel("guilty about damaging such a historic statue.");
4105 adjalign(-1);
4106 }
4107 obj->spe = 0;
4108 fracture_rock(obj);
4109 return TRUE;
4110 }
4111
4112 const char * const destroy_strings[] = { /* also used in trap.c */
4113 "freezes and shatters", "freeze and shatter", "shattered potion",
4114 "boils and explodes", "boil and explode", "boiling potion",
4115 "catches fire and burns", "catch fire and burn", "burning scroll",
4116 "catches fire and burns", "catch fire and burn", "burning book",
4117 "turns to dust and vanishes", "turn to dust and vanish", "",
4118 "breaks apart and explodes", "break apart and explode", "exploding wand"
4119 };
4120
4121 void
destroy_item(osym,dmgtyp)4122 destroy_item(osym, dmgtyp)
4123 register int osym, dmgtyp;
4124 {
4125 register struct obj *obj, *obj2;
4126 register int dmg, xresist, skip;
4127 register long i, cnt, quan;
4128 register int dindx;
4129 const char *mult;
4130
4131 for(obj = invent; obj; obj = obj2) {
4132 obj2 = obj->nobj;
4133 if(obj->oclass != osym) continue; /* test only objs of type osym */
4134 if(obj->oartifact) continue; /* don't destroy artifacts */
4135 if(obj->in_use && obj->quan == 1) continue; /* not available */
4136 xresist = skip = 0;
4137 #ifdef GCC_WARN
4138 dmg = dindx = 0;
4139 quan = 0L;
4140 #endif
4141 switch(dmgtyp) {
4142 case AD_COLD:
4143 if(osym == POTION_CLASS && obj->otyp != POT_OIL) {
4144 quan = obj->quan;
4145 dindx = 0;
4146 dmg = rnd(4);
4147 } else skip++;
4148 break;
4149 case AD_FIRE:
4150 xresist = (Fire_resistance && obj->oclass != POTION_CLASS);
4151
4152 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
4153 skip++;
4154 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
4155 skip++;
4156 if (!Blind)
4157 pline("%s glows a strange %s, but remains intact.",
4158 The(xname(obj)), hcolor("dark red"));
4159 }
4160 quan = obj->quan;
4161 switch(osym) {
4162 case POTION_CLASS:
4163 dindx = 1;
4164 dmg = rnd(6);
4165 break;
4166 case SCROLL_CLASS:
4167 dindx = 2;
4168 dmg = 1;
4169 break;
4170 case SPBOOK_CLASS:
4171 dindx = 3;
4172 dmg = 1;
4173 break;
4174 default:
4175 skip++;
4176 break;
4177 }
4178 break;
4179 case AD_ELEC:
4180 xresist = (Shock_resistance && obj->oclass != RING_CLASS);
4181 quan = obj->quan;
4182 switch(osym) {
4183 case RING_CLASS:
4184 if(obj->otyp == RIN_SHOCK_RESISTANCE)
4185 { skip++; break; }
4186 dindx = 4;
4187 dmg = 0;
4188 break;
4189 case WAND_CLASS:
4190 if(obj->otyp == WAN_LIGHTNING) { skip++; break; }
4191 #if 0
4192 if (obj == current_wand) { skip++; break; }
4193 #endif
4194 dindx = 5;
4195 dmg = rnd(10);
4196 break;
4197 default:
4198 skip++;
4199 break;
4200 }
4201 break;
4202 default:
4203 skip++;
4204 break;
4205 }
4206 if(!skip) {
4207 if (obj->in_use) --quan; /* one will be used up elsewhere */
4208 for(i = cnt = 0L; i < quan; i++)
4209 if(!rn2(3)) cnt++;
4210
4211 if(!cnt) continue;
4212 if(cnt == quan) mult = "Your";
4213 else mult = (cnt == 1L) ? "One of your" : "Some of your";
4214 pline("%s %s %s!", mult, xname(obj),
4215 (cnt > 1L) ? destroy_strings[dindx*3 + 1]
4216 : destroy_strings[dindx*3]);
4217 if(osym == POTION_CLASS && dmgtyp != AD_COLD) {
4218 if (!breathless(youmonst.data) || haseyes(youmonst.data))
4219 potionbreathe(obj);
4220 }
4221 if (obj->owornmask) {
4222 if (obj->owornmask & W_RING) /* ring being worn */
4223 Ring_gone(obj);
4224 else
4225 setnotworn(obj);
4226 }
4227 if (obj == current_wand) current_wand = 0; /* destroyed */
4228 for (i = 0; i < cnt; i++)
4229 useup(obj);
4230 if(dmg) {
4231 if(xresist) You("aren't hurt!");
4232 else {
4233 const char *how = destroy_strings[dindx * 3 + 2];
4234 boolean one = (cnt == 1L);
4235
4236 losehp(dmg, one ? how : (const char *)makeplural(how),
4237 one ? KILLED_BY_AN : KILLED_BY);
4238 exercise(A_STR, FALSE);
4239 }
4240 }
4241 }
4242 }
4243 return;
4244 }
4245
4246 int
destroy_mitem(mtmp,osym,dmgtyp)4247 destroy_mitem(mtmp, osym, dmgtyp)
4248 struct monst *mtmp;
4249 int osym, dmgtyp;
4250 {
4251 struct obj *obj, *obj2;
4252 int skip, tmp = 0;
4253 long i, cnt, quan;
4254 int dindx;
4255 boolean vis;
4256
4257 if (mtmp == &youmonst) { /* this simplifies artifact_hit() */
4258 destroy_item(osym, dmgtyp);
4259 return 0; /* arbitrary; value doesn't matter to artifact_hit() */
4260 }
4261
4262 vis = canseemon(mtmp);
4263 for(obj = mtmp->minvent; obj; obj = obj2) {
4264 obj2 = obj->nobj;
4265 if(obj->oclass != osym) continue; /* test only objs of type osym */
4266 skip = 0;
4267 quan = 0L;
4268 dindx = 0;
4269
4270 switch(dmgtyp) {
4271 case AD_COLD:
4272 if(osym == POTION_CLASS && obj->otyp != POT_OIL) {
4273 quan = obj->quan;
4274 dindx = 0;
4275 tmp++;
4276 } else skip++;
4277 break;
4278 case AD_FIRE:
4279 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
4280 skip++;
4281 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
4282 skip++;
4283 if (vis)
4284 pline("%s glows a strange %s, but remains intact.",
4285 The(distant_name(obj, xname)),
4286 hcolor("dark red"));
4287 }
4288 quan = obj->quan;
4289 switch(osym) {
4290 case POTION_CLASS:
4291 dindx = 1;
4292 tmp++;
4293 break;
4294 case SCROLL_CLASS:
4295 dindx = 2;
4296 tmp++;
4297 break;
4298 case SPBOOK_CLASS:
4299 dindx = 3;
4300 tmp++;
4301 break;
4302 default:
4303 skip++;
4304 break;
4305 }
4306 break;
4307 case AD_ELEC:
4308 quan = obj->quan;
4309 switch(osym) {
4310 case RING_CLASS:
4311 if(obj->otyp == RIN_SHOCK_RESISTANCE)
4312 { skip++; break; }
4313 dindx = 4;
4314 break;
4315 case WAND_CLASS:
4316 if(obj->otyp == WAN_LIGHTNING) { skip++; break; }
4317 dindx = 5;
4318 tmp++;
4319 break;
4320 default:
4321 skip++;
4322 break;
4323 }
4324 break;
4325 default:
4326 skip++;
4327 break;
4328 }
4329 if(!skip) {
4330 for(i = cnt = 0L; i < quan; i++)
4331 if(!rn2(3)) cnt++;
4332
4333 if(!cnt) continue;
4334 if (vis) pline("%s %s %s!",
4335 s_suffix(Monnam(mtmp)), xname(obj),
4336 (cnt > 1L) ? destroy_strings[dindx*3 + 1]
4337 : destroy_strings[dindx*3]);
4338 for(i = 0; i < cnt; i++) m_useup(mtmp, obj);
4339 }
4340 }
4341 return(tmp);
4342 }
4343
4344 int
resist(mtmp,oclass,damage,tell)4345 resist(mtmp, oclass, damage, tell)
4346 struct monst *mtmp;
4347 char oclass;
4348 int damage, tell;
4349 {
4350 int resisted;
4351 int alev, dlev;
4352
4353 /* attack level */
4354 switch (oclass) {
4355 case WAND_CLASS: alev = 12; break;
4356 case TOOL_CLASS: alev = 10; break; /* instrument */
4357 case WEAPON_CLASS: alev = 10; break; /* artifact */
4358 case SCROLL_CLASS: alev = 9; break;
4359 case POTION_CLASS: alev = 6; break;
4360 case RING_CLASS: alev = 5; break;
4361 default: alev = u.ulevel; break; /* spell */
4362 }
4363 /* defense level */
4364 dlev = (int)mtmp->m_lev;
4365 if (dlev > 50) dlev = 50;
4366 else if (dlev < 1) dlev = is_mplayer(mtmp->data) ? u.ulevel : 1;
4367
4368 resisted = rn2(100 + alev - dlev) < mtmp->data->mr;
4369 if (resisted) {
4370 if (tell) {
4371 shieldeff(mtmp->mx, mtmp->my);
4372 pline("%s resists!", Monnam(mtmp));
4373 }
4374 damage = (damage + 1) / 2;
4375 }
4376
4377 if (damage) {
4378 mtmp->mhp -= damage;
4379 if (mtmp->mhp < 1) {
4380 if(m_using) monkilled(mtmp, "", AD_RBRE);
4381 else killed(mtmp);
4382 } else if (Role_if(PM_HEALER) && flags.wounds) wounds_message(mtmp);
4383 }
4384 return(resisted);
4385 }
4386
4387 /** Lets the player make a wish.
4388 * Entering an empty string selects a random object.
4389 * Entering "nothing" returns nothing and keeps the wishing conduct.
4390 */
4391 void
makewish(magical)4392 makewish(magical)
4393 boolean magical; /**< if wishing for magical items is allowed */
4394 {
4395 char buf[BUFSZ];
4396 #ifdef LIVELOGFILE
4397 char rawbuf[BUFSZ]; /* for exact livelog reporting */
4398 #endif
4399 struct obj *otmp, nothing;
4400 int tries = 0;
4401 boolean magical_object;
4402
4403 nothing = zeroobj; /* lint suppression; only its address matters */
4404 if (flags.verbose) You("may wish for an object.");
4405 retry:
4406 do {
4407 getlin("For what do you wish?", buf);
4408 } while (buf[0] == '\033'); /* prevent accidental cancelling of a wish */
4409 #ifdef LIVELOGFILE
4410 Strcpy(rawbuf, buf);
4411 #endif
4412 if (buf[0] == '\033') buf[0] = 0;
4413
4414 /* WORKAROUND: Wishing for a random non-magical item is not easily done
4415 * with the current code.
4416 * For the time being select FOOD or WEAPON class as those
4417 * are the only classes without any magical items in it. */
4418 if (!magical && buf[0] == 0) {
4419 Strcpy(buf, rn2(2) ? "%" : ")");
4420 }
4421 /*
4422 * Note: if they wished for and got a non-object successfully,
4423 * otmp == &zeroobj. That includes gold, or an artifact that
4424 * has been denied. Wishing for "nothing" requires a separate
4425 * value to remain distinct.
4426 */
4427 otmp = readobjnam(buf, ¬hing, TRUE);
4428 if (!otmp) {
4429 pline("Nothing fitting that description exists in the game.");
4430 if (++tries < 5) goto retry;
4431 pline("%s", thats_enough_tries);
4432 otmp = readobjnam((char *)0, (struct obj *)0, TRUE);
4433 if (!otmp) return; /* for safety; should never happen */
4434 } else if (otmp == ¬hing) {
4435 /* explicitly wished for "nothing", presumeably attempting
4436 to retain wishless conduct */
4437 #ifdef LIVELOGFILE
4438 livelog_wish(buf);
4439 #endif
4440 return;
4441 }
4442 /* check if wishing for magical objects is allowed */
4443 magical_object = otmp && (otmp->oartifact || objects[otmp->otyp].oc_magic);
4444 if (!magical && magical_object) {
4445 verbalize("I'm sorry but I'm not able to provide you with magical items.");
4446 if (otmp->oartifact) artifact_exists(otmp, ONAME(otmp), FALSE);
4447 obfree(otmp, (struct obj *) 0);
4448 otmp = &zeroobj;
4449 goto retry;
4450 }
4451
4452 if (magical_object) { u.uconduct.wishmagic++; }
4453
4454 /* KMH, conduct */
4455 u.uconduct.wishes++;
4456
4457 /* Livelog patch */
4458 #ifdef LIVELOGFILE
4459 livelog_wish(rawbuf);
4460 #endif
4461
4462 if (otmp != &zeroobj) {
4463 /* The(aobjnam()) is safe since otmp is unidentified -dlc */
4464 int x = u.ux;
4465 int y = u.uy;
4466 if(otmp->oartifact == ART_EXCALIBUR && !u.uswallow) {
4467 /* try to find a neighbouring wall to stick it into
4468 (preferably an orthogonally adjacent one),
4469 otherwise on current square */
4470 if(levl[x-1][y+0].typ <=SCORR) { x += -1; y += 0; }
4471 else if(levl[x+1][y+0].typ <=SCORR) { x += 1; y += 0; }
4472 else if(levl[x+0][y-1].typ <=SCORR) { x += 0; y += -1; }
4473 else if(levl[x+0][y+1].typ <=SCORR) { x += 0; y += 1; }
4474 else if(levl[x-1][y-1].typ <=SCORR) { x += -1; y += -1; }
4475 else if(levl[x-1][y+1].typ <=SCORR) { x += -1; y += 1; }
4476 else if(levl[x+1][y-1].typ <=SCORR) { x += 1; y += -1; }
4477 else if(levl[x+1][y+1].typ <=SCORR) { x += 1; y += 1; }
4478 }
4479 if(!(x==u.ux && y==u.uy)) {
4480 pline("A sword flashes through the air and embeds itself in %s next to you!",
4481 IS_TREE(levl[x][y].typ) ? "a tree" :
4482 (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR) ? "the wall" :
4483 closed_door(x,y) ? "a door" :
4484 "the stone");
4485 place_object(otmp, x, y);
4486 stackobj(otmp);
4487 if(Blind && Levitation)
4488 map_object(otmp, 0);
4489 newsym(x,y); /* remap location */
4490 } else {
4491 (void) hold_another_object(otmp, u.uswallow ?
4492 "Oops! %s out of your reach!" :
4493 (Is_airlevel(&u.uz) ||
4494 Is_waterlevel(&u.uz) ||
4495 levl[x][y].typ < IRONBARS ||
4496 levl[x][y].typ >= ICE) ?
4497 "Oops! %s away from you!" :
4498 "Oops! %s to the floor!",
4499 The(aobjnam(otmp,
4500 Is_airlevel(&u.uz) || u.uinwater ?
4501 "slip" : "drop")),
4502 (const char *)0);
4503 }
4504 }
4505 }
4506
4507 /*zap.c*/
4508