]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - hack/hack.zap.c
Make mostly gcc -W clean, and other cleanup:
[bsdgames-darwin.git] / hack / hack.zap.c
1 /* $NetBSD: hack.zap.c,v 1.5 2001/03/25 20:44:04 jsm Exp $ */
2
3 /*
4 * Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985.
5 */
6
7 #include <sys/cdefs.h>
8 #ifndef lint
9 __RCSID("$NetBSD: hack.zap.c,v 1.5 2001/03/25 20:44:04 jsm Exp $");
10 #endif /* not lint */
11
12 #include "hack.h"
13 #include "extern.h"
14
15 const char *const fl[] = {
16 "magic missile",
17 "bolt of fire",
18 "sleep ray",
19 "bolt of cold",
20 "death ray"
21 };
22
23 /* Routines for IMMEDIATE wands. */
24 /* bhitm: monster mtmp was hit by the effect of wand otmp */
25 void
26 bhitm(mtmp, otmp)
27 struct monst *mtmp;
28 struct obj *otmp;
29 {
30 wakeup(mtmp);
31 switch (otmp->otyp) {
32 case WAN_STRIKING:
33 if (u.uswallow || rnd(20) < 10 + mtmp->data->ac) {
34 int tmp = d(2, 12);
35 hit("wand", mtmp, exclam(tmp));
36 mtmp->mhp -= tmp;
37 if (mtmp->mhp < 1)
38 killed(mtmp);
39 } else
40 miss("wand", mtmp);
41 break;
42 case WAN_SLOW_MONSTER:
43 mtmp->mspeed = MSLOW;
44 break;
45 case WAN_SPEED_MONSTER:
46 mtmp->mspeed = MFAST;
47 break;
48 case WAN_UNDEAD_TURNING:
49 if (strchr(UNDEAD, mtmp->data->mlet)) {
50 mtmp->mhp -= rnd(8);
51 if (mtmp->mhp < 1)
52 killed(mtmp);
53 else
54 mtmp->mflee = 1;
55 }
56 break;
57 case WAN_POLYMORPH:
58 if (newcham(mtmp, &mons[rn2(CMNUM)]))
59 objects[otmp->otyp].oc_name_known = 1;
60 break;
61 case WAN_CANCELLATION:
62 mtmp->mcan = 1;
63 break;
64 case WAN_TELEPORTATION:
65 rloc(mtmp);
66 break;
67 case WAN_MAKE_INVISIBLE:
68 mtmp->minvis = 1;
69 break;
70 #ifdef WAN_PROBING
71 case WAN_PROBING:
72 mstatusline(mtmp);
73 break;
74 #endif /* WAN_PROBING */
75 default:
76 impossible("What an interesting wand (%u)", otmp->otyp);
77 }
78 }
79
80 int
81 bhito(obj, otmp) /* object obj was hit by the effect of wand
82 * otmp */
83 struct obj *obj, *otmp; /* returns TRUE if sth was done */
84 {
85 int res = TRUE;
86
87 if (obj == uball || obj == uchain)
88 res = FALSE;
89 else
90 switch (otmp->otyp) {
91 case WAN_POLYMORPH:
92 /*
93 * preserve symbol and quantity, but turn rocks into
94 * gems
95 */
96 mkobj_at((obj->otyp == ROCK || obj->otyp == ENORMOUS_ROCK)
97 ? GEM_SYM : obj->olet,
98 obj->ox, obj->oy)->quan = obj->quan;
99 delobj(obj);
100 break;
101 case WAN_STRIKING:
102 if (obj->otyp == ENORMOUS_ROCK)
103 fracture_rock(obj);
104 else
105 res = FALSE;
106 break;
107 case WAN_CANCELLATION:
108 if (obj->spe && obj->olet != AMULET_SYM) {
109 obj->known = 0;
110 obj->spe = 0;
111 }
112 break;
113 case WAN_TELEPORTATION:
114 rloco(obj);
115 break;
116 case WAN_MAKE_INVISIBLE:
117 obj->oinvis = 1;
118 break;
119 case WAN_UNDEAD_TURNING:
120 res = revive(obj);
121 break;
122 case WAN_SLOW_MONSTER: /* no effect on objects */
123 case WAN_SPEED_MONSTER:
124 #ifdef WAN_PROBING
125 case WAN_PROBING:
126 #endif /* WAN_PROBING */
127 res = FALSE;
128 break;
129 default:
130 impossible("What an interesting wand (%u)", otmp->otyp);
131 }
132 return (res);
133 }
134
135 int
136 dozap()
137 {
138 struct obj *obj;
139 xchar zx, zy;
140
141 obj = getobj("/", "zap");
142 if (!obj)
143 return (0);
144 if (obj->spe < 0 || (obj->spe == 0 && rn2(121))) {
145 pline("Nothing Happens.");
146 return (1);
147 }
148 if (obj->spe == 0)
149 pline("You wrest one more spell from the worn-out wand.");
150 if (!(objects[obj->otyp].bits & NODIR) && !getdir(1))
151 return (1); /* make him pay for knowing !NODIR */
152 obj->spe--;
153 if (objects[obj->otyp].bits & IMMEDIATE) {
154 if (u.uswallow)
155 bhitm(u.ustuck, obj);
156 else if (u.dz) {
157 if (u.dz > 0) {
158 struct obj *otmp = o_at(u.ux, u.uy);
159 if (otmp)
160 (void) bhito(otmp, obj);
161 }
162 } else
163 (void) bhit(u.dx, u.dy, rn1(8, 6), 0, bhitm, bhito, obj);
164 } else {
165 switch (obj->otyp) {
166 case WAN_LIGHT:
167 litroom(TRUE);
168 break;
169 case WAN_SECRET_DOOR_DETECTION:
170 if (!findit())
171 return (1);
172 break;
173 case WAN_CREATE_MONSTER:
174 {
175 int cnt = 1;
176 if (!rn2(23))
177 cnt += rn2(7) + 1;
178 while (cnt--)
179 (void) makemon((struct permonst *) 0, u.ux, u.uy);
180 }
181 break;
182 case WAN_WISHING:
183 {
184 char buf[BUFSZ];
185 struct obj *otmp;
186 if (u.uluck + rn2(5) < 0) {
187 pline("Unfortunately, nothing happens.");
188 break;
189 }
190 pline("You may wish for an object. What do you want? ");
191 getlin(buf);
192 if (buf[0] == '\033')
193 buf[0] = 0;
194 otmp = readobjnam(buf);
195 otmp = addinv(otmp);
196 prinv(otmp);
197 break;
198 }
199 case WAN_DIGGING:
200 /*
201 * Original effect (approximately): from CORR: dig
202 * until we pierce a wall from ROOM: piece wall and
203 * dig until we reach an ACCESSIBLE place. Currently:
204 * dig for digdepth positions; also down on request
205 * of Lennart Augustsson.
206 */
207 {
208 struct rm *room;
209 int digdepth;
210 if (u.uswallow) {
211 struct monst *mtmp = u.ustuck;
212
213 pline("You pierce %s's stomach wall!",
214 monnam(mtmp));
215 mtmp->mhp = 1; /* almost dead */
216 unstuck(mtmp);
217 mnexto(mtmp);
218 break;
219 }
220 if (u.dz) {
221 if (u.dz < 0) {
222 pline("You loosen a rock from the ceiling.");
223 pline("It falls on your head!");
224 losehp(1, "falling rock");
225 mksobj_at(ROCK, u.ux, u.uy);
226 fobj->quan = 1;
227 stackobj(fobj);
228 if (Invisible)
229 newsym(u.ux, u.uy);
230 } else {
231 dighole();
232 }
233 break;
234 }
235 zx = u.ux + u.dx;
236 zy = u.uy + u.dy;
237 digdepth = 8 + rn2(18);
238 Tmp_at(-1, '*'); /* open call */
239 while (--digdepth >= 0) {
240 if (!isok(zx, zy))
241 break;
242 room = &levl[zx][zy];
243 Tmp_at(zx, zy);
244 if (!xdnstair) {
245 if (zx < 3 || zx > COLNO - 3 ||
246 zy < 3 || zy > ROWNO - 3)
247 break;
248 if (room->typ == HWALL ||
249 room->typ == VWALL) {
250 room->typ = ROOM;
251 break;
252 }
253 } else if (room->typ == HWALL || room->typ == VWALL ||
254 room->typ == SDOOR || room->typ == LDOOR) {
255 room->typ = DOOR;
256 digdepth -= 2;
257 } else if (room->typ == SCORR || !room->typ) {
258 room->typ = CORR;
259 digdepth--;
260 }
261 mnewsym(zx, zy);
262 zx += u.dx;
263 zy += u.dy;
264 }
265 mnewsym(zx, zy); /* not always necessary */
266 Tmp_at(-1, -1); /* closing call */
267 break;
268 }
269 default:
270 buzz((int) obj->otyp - WAN_MAGIC_MISSILE,
271 u.ux, u.uy, u.dx, u.dy);
272 break;
273 }
274 if (!objects[obj->otyp].oc_name_known) {
275 objects[obj->otyp].oc_name_known = 1;
276 more_experienced(0, 10);
277 }
278 }
279 return (1);
280 }
281
282 const char *
283 exclam(force)
284 int force;
285 {
286 /* force == 0 occurs e.g. with sleep ray */
287 /*
288 * note that large force is usual with wands so that !! would require
289 * information about hand/weapon/wand
290 */
291 return ((force < 0) ? "?" : (force <= 4) ? "." : "!");
292 }
293
294 void
295 hit(str, mtmp, force)
296 const char *str;
297 struct monst *mtmp;
298 const char *force; /* usually either "." or "!" */
299 {
300 if (!cansee(mtmp->mx, mtmp->my))
301 pline("The %s hits it.", str);
302 else
303 pline("The %s hits %s%s", str, monnam(mtmp), force);
304 }
305
306 void
307 miss(str, mtmp)
308 const char *str;
309 struct monst *mtmp;
310 {
311 if (!cansee(mtmp->mx, mtmp->my))
312 pline("The %s misses it.", str);
313 else
314 pline("The %s misses %s.", str, monnam(mtmp));
315 }
316
317 /*
318 * bhit: called when a weapon is thrown (sym = obj->olet) or when an
319 * IMMEDIATE wand is zapped (sym = 0); the weapon falls down at end of range
320 * or when a monster is hit; the monster is returned, and bhitpos is set to
321 * the final position of the weapon thrown; the ray of a wand may affect
322 * several objects and monsters on its path - for each of these an argument
323 * function is called.
324 */
325 /* check !u.uswallow before calling bhit() */
326
327 struct monst *
328 bhit(ddx, ddy, range, sym, fhitm, fhito, obj)
329 int ddx, ddy, range; /* direction and range */
330 char sym; /* symbol displayed on path */
331 /* fns called when mon/obj hit */
332 void (*fhitm) __P((struct monst *, struct obj *));
333 int (*fhito) __P((struct obj *, struct obj *));
334 struct obj *obj; /* 2nd arg to fhitm/fhito */
335 {
336 struct monst *mtmp;
337 struct obj *otmp;
338 int typ;
339
340 bhitpos.x = u.ux;
341 bhitpos.y = u.uy;
342
343 if (sym)
344 tmp_at(-1, sym);/* open call */
345 while (range-- > 0) {
346 bhitpos.x += ddx;
347 bhitpos.y += ddy;
348 typ = levl[bhitpos.x][bhitpos.y].typ;
349 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != NULL) {
350 if (sym) {
351 tmp_at(-1, -1); /* close call */
352 return (mtmp);
353 }
354 (*fhitm) (mtmp, obj);
355 range -= 3;
356 }
357 if (fhito && (otmp = o_at(bhitpos.x, bhitpos.y))) {
358 if ((*fhito) (otmp, obj))
359 range--;
360 }
361 if (!ZAP_POS(typ)) {
362 bhitpos.x -= ddx;
363 bhitpos.y -= ddy;
364 break;
365 }
366 if (sym)
367 tmp_at(bhitpos.x, bhitpos.y);
368 }
369
370 /* leave last symbol unless in a pool */
371 if (sym)
372 tmp_at(-1, (levl[bhitpos.x][bhitpos.y].typ == POOL) ? -1 : 0);
373 return (0);
374 }
375
376 struct monst *
377 boomhit(int dx, int dy)
378 {
379 int i, ct;
380 struct monst *mtmp;
381 char sym = ')';
382
383 bhitpos.x = u.ux;
384 bhitpos.y = u.uy;
385
386 for (i = 0; i < 8; i++)
387 if (xdir[i] == dx && ydir[i] == dy)
388 break;
389 tmp_at(-1, sym); /* open call */
390 for (ct = 0; ct < 10; ct++) {
391 if (i == 8)
392 i = 0;
393 sym = ')' + '(' - sym;
394 tmp_at(-2, sym);/* change let call */
395 dx = xdir[i];
396 dy = ydir[i];
397 bhitpos.x += dx;
398 bhitpos.y += dy;
399 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != NULL) {
400 tmp_at(-1, -1);
401 return (mtmp);
402 }
403 if (!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ)) {
404 bhitpos.x -= dx;
405 bhitpos.y -= dy;
406 break;
407 }
408 if (bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
409 if (rn2(20) >= 10 + u.ulevel) { /* we hit ourselves */
410 (void) thitu(10, rnd(10), "boomerang");
411 break;
412 } else {/* we catch it */
413 tmp_at(-1, -1);
414 pline("Skillfully, you catch the boomerang.");
415 return (&youmonst);
416 }
417 }
418 tmp_at(bhitpos.x, bhitpos.y);
419 if (ct % 5 != 0)
420 i++;
421 }
422 tmp_at(-1, -1); /* do not leave last symbol */
423 return (0);
424 }
425
426 char
427 dirlet(dx, dy)
428 int dx, dy;
429 {
430 return
431 (dx == dy) ? '\\' : (dx && dy) ? '/' : dx ? '-' : '|';
432 }
433
434 /* type == -1: monster spitting fire at you */
435 /* type == -1,-2,-3: bolts sent out by wizard */
436 /* called with dx = dy = 0 with vertical bolts */
437 void
438 buzz(type, sx, sy, dx, dy)
439 int type;
440 xchar sx, sy;
441 int dx, dy;
442 {
443 int abstype = abs(type);
444 const char *fltxt = (type == -1) ? "blaze of fire" : fl[abstype];
445 struct rm *lev;
446 xchar range;
447 struct monst *mon;
448
449 if (u.uswallow) {
450 int tmp;
451
452 if (type < 0)
453 return;
454 tmp = zhit(u.ustuck, type);
455 pline("The %s rips into %s%s",
456 fltxt, monnam(u.ustuck), exclam(tmp));
457 return;
458 }
459 if (type < 0)
460 pru();
461 range = rn1(7, 7);
462 Tmp_at(-1, dirlet(dx, dy)); /* open call */
463 while (range-- > 0) {
464 sx += dx;
465 sy += dy;
466 if ((lev = &levl[sx][sy])->typ)
467 Tmp_at(sx, sy);
468 else {
469 int bounce = 0;
470 if (cansee(sx - dx, sy - dy))
471 pline("The %s bounces!", fltxt);
472 if (ZAP_POS(levl[sx][sy - dy].typ))
473 bounce = 1;
474 if (ZAP_POS(levl[sx - dx][sy].typ)) {
475 if (!bounce || rn2(2))
476 bounce = 2;
477 }
478 switch (bounce) {
479 case 0:
480 dx = -dx;
481 dy = -dy;
482 continue;
483 case 1:
484 dy = -dy;
485 sx -= dx;
486 break;
487 case 2:
488 dx = -dx;
489 sy -= dy;
490 break;
491 }
492 Tmp_at(-2, dirlet(dx, dy));
493 continue;
494 }
495 if (lev->typ == POOL && abstype == 1 /* fire */ ) {
496 range -= 3;
497 lev->typ = ROOM;
498 if (cansee(sx, sy)) {
499 mnewsym(sx, sy);
500 pline("The water evaporates.");
501 } else
502 pline("You hear a hissing sound.");
503 }
504 if ((mon = m_at(sx, sy)) &&
505 (type != -1 || mon->data->mlet != 'D')) {
506 wakeup(mon);
507 if (rnd(20) < 18 + mon->data->ac) {
508 int tmp = zhit(mon, abstype);
509 if (mon->mhp < 1) {
510 if (type < 0) {
511 if (cansee(mon->mx, mon->my))
512 pline("%s is killed by the %s!",
513 Monnam(mon), fltxt);
514 mondied(mon);
515 } else
516 killed(mon);
517 } else
518 hit(fltxt, mon, exclam(tmp));
519 range -= 2;
520 } else
521 miss(fltxt, mon);
522 } else if (sx == u.ux && sy == u.uy) {
523 nomul(0);
524 if (rnd(20) < 18 + u.uac) {
525 int dam = 0;
526 range -= 2;
527 pline("The %s hits you!", fltxt);
528 switch (abstype) {
529 case 0:
530 dam = d(2, 6);
531 break;
532 case 1:
533 if (Fire_resistance)
534 pline("You don't feel hot!");
535 else
536 dam = d(6, 6);
537 if (!rn2(3))
538 burn_scrolls();
539 break;
540 case 2:
541 nomul(-rnd(25)); /* sleep ray */
542 break;
543 case 3:
544 if (Cold_resistance)
545 pline("You don't feel cold!");
546 else
547 dam = d(6, 6);
548 break;
549 case 4:
550 u.uhp = -1;
551 }
552 losehp(dam, fltxt);
553 } else
554 pline("The %s whizzes by you!", fltxt);
555 stop_occupation();
556 }
557 if (!ZAP_POS(lev->typ)) {
558 int bounce = 0, rmn;
559 if (cansee(sx, sy))
560 pline("The %s bounces!", fltxt);
561 range--;
562 if (!dx || !dy || !rn2(20)) {
563 dx = -dx;
564 dy = -dy;
565 } else {
566 if (ZAP_POS(rmn = levl[sx][sy - dy].typ) &&
567 (IS_ROOM(rmn) || ZAP_POS(levl[sx + dx][sy - dy].typ)))
568 bounce = 1;
569 if (ZAP_POS(rmn = levl[sx - dx][sy].typ) &&
570 (IS_ROOM(rmn) || ZAP_POS(levl[sx - dx][sy + dy].typ)))
571 if (!bounce || rn2(2))
572 bounce = 2;
573
574 switch (bounce) {
575 case 0:
576 dy = -dy;
577 dx = -dx;
578 break;
579 case 1:
580 dy = -dy;
581 break;
582 case 2:
583 dx = -dx;
584 break;
585 }
586 Tmp_at(-2, dirlet(dx, dy));
587 }
588 }
589 }
590 Tmp_at(-1, -1);
591 }
592
593 int
594 zhit(mon, type) /* returns damage to mon */
595 struct monst *mon;
596 int type;
597 {
598 int tmp = 0;
599
600 switch (type) {
601 case 0: /* magic missile */
602 tmp = d(2, 6);
603 break;
604 case -1: /* Dragon blazing fire */
605 case 1: /* fire */
606 if (strchr("Dg", mon->data->mlet))
607 break;
608 tmp = d(6, 6);
609 if (strchr("YF", mon->data->mlet))
610 tmp += 7;
611 break;
612 case 2: /* sleep */
613 mon->mfroz = 1;
614 break;
615 case 3: /* cold */
616 if (strchr("YFgf", mon->data->mlet))
617 break;
618 tmp = d(6, 6);
619 if (mon->data->mlet == 'D')
620 tmp += 7;
621 break;
622 case 4: /* death */
623 if (strchr(UNDEAD, mon->data->mlet))
624 break;
625 tmp = mon->mhp + 1;
626 break;
627 }
628 mon->mhp -= tmp;
629 return (tmp);
630 }
631
632 #define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\
633 ? 'a' + (otyp - DEAD_ACID_BLOB)\
634 : '@' + (otyp - DEAD_HUMAN))
635 int
636 revive(obj)
637 struct obj *obj;
638 {
639 struct monst *mtmp = NULL;
640
641 if (obj->olet == FOOD_SYM && obj->otyp > CORPSE) {
642 /* do not (yet) revive shopkeepers */
643 /*
644 * Note: this might conceivably produce two monsters at the
645 * same position - strange, but harmless
646 */
647 mtmp = mkmon_at(CORPSE_I_TO_C(obj->otyp), obj->ox, obj->oy);
648 delobj(obj);
649 }
650 return (!!mtmp); /* TRUE if some monster created */
651 }
652
653 void
654 rloco(obj)
655 struct obj *obj;
656 {
657 int tx, ty, otx, oty;
658
659 otx = obj->ox;
660 oty = obj->oy;
661 do {
662 tx = rn1(COLNO - 3, 2);
663 ty = rn2(ROWNO);
664 } while (!goodpos(tx, ty));
665 obj->ox = tx;
666 obj->oy = ty;
667 if (cansee(otx, oty))
668 newsym(otx, oty);
669 }
670
671 void
672 fracture_rock(obj) /* fractured by pick-axe or wand of striking */
673 struct obj *obj; /* no texts here! */
674 {
675 /* unpobj(obj); */
676 obj->otyp = ROCK;
677 obj->quan = 7 + rn2(60);
678 obj->owt = weight(obj);
679 obj->olet = WEAPON_SYM;
680 if (cansee(obj->ox, obj->oy))
681 prl(obj->ox, obj->oy);
682 }
683
684 void
685 burn_scrolls()
686 {
687 struct obj *obj, *obj2;
688 int cnt = 0;
689
690 for (obj = invent; obj; obj = obj2) {
691 obj2 = obj->nobj;
692 if (obj->olet == SCROLL_SYM) {
693 cnt++;
694 useup(obj);
695 }
696 }
697 if (cnt > 1) {
698 pline("Your scrolls catch fire!");
699 losehp(cnt, "burning scrolls");
700 } else if (cnt) {
701 pline("Your scroll catches fire!");
702 losehp(1, "burning scroll");
703 }
704 }