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