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