Merge branch 'vendor/OPENSSL'
[dragonfly.git] / games / hack / hack.zap.c
1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.zap.c - version 1.0.3 */
3 /* $FreeBSD: src/games/hack/hack.zap.c,v 1.4 1999/11/16 10:26:38 marcel Exp $ */
4 /* $DragonFly: src/games/hack/hack.zap.c,v 1.5 2006/08/21 19:45:32 pavalos Exp $ */
5
6 #include "hack.h"
7
8 extern struct monst youmonst;
9
10 static const char *fl[]= {
11         "magic missile",
12         "bolt of fire",
13         "sleep ray",
14         "bolt of cold",
15         "death ray"
16 };
17
18 static void bhitm(struct monst *, struct obj *);
19 static bool bhito(struct obj *, struct obj *);
20 static char dirlet(int, int);
21 static int zhit(struct monst *, int);
22 static bool revive(struct obj *);
23 static void rloco(struct obj *);
24 static void burn_scrolls(void);
25
26 /* Routines for IMMEDIATE wands. */
27 /* bhitm: monster mtmp was hit by the effect of wand otmp */
28 static void
29 bhitm(struct monst *mtmp, struct obj *otmp)
30 {
31         wakeup(mtmp);
32         switch (otmp->otyp) {
33         case WAN_STRIKING:
34                 if (u.uswallow || rnd(20) < 10 + mtmp->data->ac) {
35                         int tmp = d(2, 12);
36                         hit("wand", mtmp, exclam(tmp));
37                         mtmp->mhp -= tmp;
38                         if (mtmp->mhp < 1)
39                                 killed(mtmp);
40                 } else
41                         miss("wand", mtmp);
42                 break;
43         case WAN_SLOW_MONSTER:
44                 mtmp->mspeed = MSLOW;
45                 break;
46         case WAN_SPEED_MONSTER:
47                 mtmp->mspeed = MFAST;
48                 break;
49         case WAN_UNDEAD_TURNING:
50                 if (strchr(UNDEAD, mtmp->data->mlet)) {
51                         mtmp->mhp -= rnd(8);
52                         if (mtmp->mhp < 1)
53                                 killed(mtmp);
54                         else
55                                 mtmp->mflee = 1;
56                 }
57                 break;
58         case WAN_POLYMORPH:
59                 if (newcham(mtmp, &mons[rn2(CMNUM)]))
60                         objects[otmp->otyp].oc_name_known = 1;
61                 break;
62         case WAN_CANCELLATION:
63                 mtmp->mcan = 1;
64                 break;
65         case WAN_TELEPORTATION:
66                 rloc(mtmp);
67                 break;
68         case WAN_MAKE_INVISIBLE:
69                 mtmp->minvis = 1;
70                 break;
71 #ifdef WAN_PROBING
72         case WAN_PROBING:
73                 mstatusline(mtmp);
74                 break;
75 #endif /* WAN_PROBING */
76         default:
77                 impossible("What an interesting wand (%u)", otmp->otyp);
78         }
79 }
80
81 /*
82  * object obj was hit by the effect of wand otmp
83  * returns TRUE if sth was done
84  */
85 static bool
86 bhito(struct obj *obj, struct obj *otmp)
87 {
88         int res = TRUE;
89
90         if (obj == uball || obj == uchain)
91                 res = FALSE;
92         else
93                 switch (otmp->otyp) {
94                 case WAN_POLYMORPH:
95                         /* preserve symbol and quantity, but turn rocks into gems */
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(void)
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                                         bhito(otmp, obj);
161                         }
162                 } else
163                         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                                         makemon(NULL, 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):
202                          * from CORR: dig until we pierce a wall
203                          * from ROOM: piece wall and dig until we reach
204                          * an ACCESSIBLE place.
205                          * Currently: dig for digdepth positions;
206                          * also down on request of Lennart Augustsson.
207                          */
208                         {
209                                 struct rm *room;
210                                 int digdepth;
211                                 if (u.uswallow) {
212                                         struct monst *mtmp = u.ustuck;
213
214                                         pline("You pierce %s's stomach wall!",
215                                             monnam(mtmp));
216                                         mtmp->mhp = 1;  /* almost dead */
217                                         unstuck(mtmp);
218                                         mnexto(mtmp);
219                                         break;
220                                 }
221                                 if (u.dz) {
222                                         if (u.dz < 0) {
223                                                 pline("You loosen a rock from the ceiling.");
224                                                 pline("It falls on your head!");
225                                                 losehp(1, "falling rock");
226                                                 mksobj_at(ROCK, u.ux, u.uy);
227                                                 fobj->quan = 1;
228                                                 stackobj(fobj);
229                                                 if (Invisible)
230                                                         newsym(u.ux, u.uy);
231                                         } else
232                                                 dighole();
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(int force)
284 {
285         /* force == 0 occurs e.g. with sleep ray */
286         /* note that large force is usual with wands so that !! would
287                 require information about hand/weapon/wand */
288         return ((force < 0) ? "?" : (force <= 4) ? "." : "!");
289 }
290
291 void
292 hit(const char *str, struct monst *mtmp, const char *force)
293 {
294         /* force: usually either "." or "!" */
295         if (!cansee(mtmp->mx, mtmp->my))
296                 pline("The %s hits it.", str);
297         else
298                 pline("The %s hits %s%s", str, monnam(mtmp), force);
299 }
300
301 void
302 miss(const char *str, struct monst *mtmp)
303 {
304         if (!cansee(mtmp->mx, mtmp->my))
305                 pline("The %s misses it.", str);
306         else
307                 pline("The %s misses %s.", str, monnam(mtmp));
308 }
309
310 /*
311  * bhit: called when a weapon is thrown (sym = obj->olet) or when an
312  * IMMEDIATE wand is zapped (sym = 0); the weapon falls down at end of range
313  * or when a monster is hit; the monster is returned, and bhitpos is set to
314  * the final position of the weapon thrown; the ray of a wand may affect
315  * several objects and monsters on its path - for each of these an argument
316  * function is called.
317  */
318 /* check !u.uswallow before calling bhit() */
319
320 /* ddx, ddy, range:  direction and range
321  * sym:  symbol displayed on path
322  * fhitm, fhito:  fns called when mon/obj hit
323  * obj:  2nd arg to fhitm/fhito
324  */
325 struct monst *
326 bhit(int ddx, int ddy, int range, char sym,
327      void (*fhitm)(struct monst *, struct obj *),
328      bool (*fhito)(struct obj *, struct obj *), struct obj *obj)
329 {
330         struct monst *mtmp;
331         struct obj *otmp;
332         int typ;
333
334         bhitpos.x = u.ux;
335         bhitpos.y = u.uy;
336
337         if (sym)        /* open call */
338                 tmp_at(-1, sym);
339         while (range-- > 0) {
340                 bhitpos.x += ddx;
341                 bhitpos.y += ddy;
342                 typ = levl[bhitpos.x][bhitpos.y].typ;
343                 if ((mtmp = m_at(bhitpos.x, bhitpos.y))) {
344                         if (sym) {
345                                 tmp_at(-1, -1); /* close call */
346                                 return (mtmp);
347                         }
348                         (*fhitm)(mtmp, obj);
349                         range -= 3;
350                 }
351                 if (fhito && (otmp = o_at(bhitpos.x, bhitpos.y))) {
352                         if ((*fhito)(otmp, obj))
353                                 range--;
354                 }
355                 if (!ZAP_POS(typ)) {
356                         bhitpos.x -= ddx;
357                         bhitpos.y -= ddy;
358                         break;
359                 }
360                 if (sym)
361                         tmp_at(bhitpos.x, bhitpos.y);
362         }
363
364         /* leave last symbol unless in a pool */
365         if (sym)
366                 tmp_at(-1, (levl[bhitpos.x][bhitpos.y].typ == POOL) ? -1 : 0);
367         return (0);
368 }
369
370 struct monst *
371 boomhit(int dx, int dy)
372 {
373         int i, ct;
374         struct monst *mtmp;
375         char sym = ')';
376
377         bhitpos.x = u.ux;
378         bhitpos.y = u.uy;
379
380         for (i = 0; i < 8; i++)
381                 if (xdir[i] == dx && ydir[i] == dy)
382                         break;
383         tmp_at(-1, sym);        /* open call */
384         for (ct = 0; ct < 10; ct++) {
385                 if (i == 8)
386                         i = 0;
387                 sym = ')' + '(' - sym;
388                 tmp_at(-2, sym);        /* change let call */
389                 dx = xdir[i];
390                 dy = ydir[i];
391                 bhitpos.x += dx;
392                 bhitpos.y += dy;
393                 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != NULL) {
394                         tmp_at(-1, -1);
395                         return (mtmp);
396                 }
397                 if (!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ)) {
398                         bhitpos.x -= dx;
399                         bhitpos.y -= dy;
400                         break;
401                 }
402                 if (bhitpos.x == u.ux && bhitpos.y == u.uy) {   /* ct == 9 */
403                         if (rn2(20) >= 10 + u.ulevel) { /* we hit ourselves */
404                                 thitu(10, rnd(10), "boomerang");
405                                 break;
406                         } else {        /* we catch it */
407                                 tmp_at(-1, -1);
408                                 pline("Skillfully, you catch the boomerang.");
409                                 return (&youmonst);
410                         }
411                 }
412                 tmp_at(bhitpos.x, bhitpos.y);
413                 if (ct % 5 != 0)
414                         i++;
415         }
416         tmp_at(-1, -1);         /* do not leave last symbol */
417         return (0);
418 }
419
420 static char
421 dirlet(int dx, int dy)
422 {
423         return
424                 (dx == dy) ? '\\' : (dx && dy) ? '/' : dx ? '-' : '|';
425 }
426
427 /* type == -1: monster spitting fire at you */
428 /* type == -1,-2,-3: bolts sent out by wizard */
429 /* called with dx = dy = 0 with vertical bolts */
430 void
431 buzz(int type, xchar sx, xchar sy, int dx, int dy)
432 {
433         int abstype = abs(type);
434         const char *fltxt = (type == -1) ? "blaze of fire" : fl[abstype];
435         struct rm *lev;
436         xchar range;
437         struct monst *mon;
438
439         if (u.uswallow) {
440                 int tmp;
441
442                 if (type < 0)
443                         return;
444                 tmp = zhit(u.ustuck, type);
445                 pline("The %s rips into %s%s",
446                       fltxt, monnam(u.ustuck), exclam(tmp));
447                 return;
448         }
449         if (type < 0)
450                 pru();
451         range = rn1(7, 7);
452         Tmp_at(-1, dirlet(dx, dy));     /* open call */
453         while (range-- > 0) {
454                 sx += dx;
455                 sy += dy;
456                 if ((lev = &levl[sx][sy])->typ)
457                         Tmp_at(sx, sy);
458                 else {
459                         int bounce = 0;
460                         if (cansee(sx - dx, sy - dy))
461                                 pline("The %s bounces!", fltxt);
462                         if (ZAP_POS(levl[sx][sy - dy].typ))
463                                 bounce = 1;
464                         if (ZAP_POS(levl[sx - dx][sy].typ)) {
465                                 if (!bounce || rn2(2))
466                                         bounce = 2;
467                         }
468                         switch (bounce) {
469                         case 0:
470                                 dx = -dx;
471                                 dy = -dy;
472                                 continue;
473                         case 1:
474                                 dy = -dy;
475                                 sx -= dx;
476                                 break;
477                         case 2:
478                                 dx = -dx;
479                                 sy -= dy;
480                                 break;
481                         }
482                         Tmp_at(-2, dirlet(dx, dy));
483                         continue;
484                 }
485                 if (lev->typ == POOL && abstype == 1 /* fire */) {
486                         range -= 3;
487                         lev->typ = ROOM;
488                         if (cansee(sx, sy)) {
489                                 mnewsym(sx, sy);
490                                 pline("The water evaporates.");
491                         } else
492                                 pline("You hear a hissing sound.");
493                 }
494                 if ((mon = m_at(sx, sy)) &&
495                     (type != -1 || mon->data->mlet != 'D')) {
496                         wakeup(mon);
497                         if (rnd(20) < 18 + mon->data->ac) {
498                                 int tmp = zhit(mon, abstype);
499                                 if (mon->mhp < 1) {
500                                         if (type < 0) {
501                                                 if (cansee(mon->mx, mon->my))
502                                                         pline("%s is killed by the %s!",
503                                                             Monnam(mon), fltxt);
504                                                 mondied(mon);
505                                         } else
506                                                 killed(mon);
507                                 } else
508                                         hit(fltxt, mon, exclam(tmp));
509                                 range -= 2;
510                         } else
511                                 miss(fltxt, mon);
512                 } else if (sx == u.ux && sy == u.uy) {
513                         nomul(0);
514                         if (rnd(20) < 18 + u.uac) {
515                                 int dam = 0;
516                                 range -= 2;
517                                 pline("The %s hits you!", fltxt);
518                                 switch (abstype) {
519                                 case 0:
520                                         dam = d(2, 6);
521                                         break;
522                                 case 1:
523                                         if (Fire_resistance)
524                                                 pline("You don't feel hot!");
525                                         else
526                                                 dam = d(6, 6);
527                                         if (!rn2(3))
528                                                 burn_scrolls();
529                                         break;
530                                 case 2:
531                                         nomul(-rnd(25));        /* sleep ray */
532                                         break;
533                                 case 3:
534                                         if (Cold_resistance)
535                                                 pline("You don't feel cold!");
536                                         else
537                                                 dam = d(6, 6);
538                                         break;
539                                 case 4:
540                                         u.uhp = -1;
541                                 }
542                                 losehp(dam, fltxt);
543                         } else
544                                 pline("The %s whizzes by you!", fltxt);
545                         stop_occupation();
546                 }
547                 if (!ZAP_POS(lev->typ)) {
548                         int bounce = 0, rmn;
549                         if (cansee(sx, sy))
550                                 pline("The %s bounces!", fltxt);
551                         range--;
552                         if (!dx || !dy || !rn2(20)) {
553                                 dx = -dx;
554                                 dy = -dy;
555                         } else {
556                                 if (ZAP_POS(rmn = levl[sx][sy - dy].typ) &&
557                                     (IS_ROOM(rmn) || ZAP_POS(levl[sx + dx][sy - dy].typ)))
558                                         bounce = 1;
559                                 if (ZAP_POS(rmn = levl[sx - dx][sy].typ) &&
560                                     (IS_ROOM(rmn) || ZAP_POS(levl[sx - dx][sy + dy].typ)))
561                                         if (!bounce || rn2(2))
562                                                 bounce = 2;
563
564                                 switch (bounce) {
565                                 case 0:
566                                         dy = -dy;
567                                         dx = -dx;
568                                         break;
569                                 case 1:
570                                         dy = -dy;
571                                         break;
572                                 case 2:
573                                         dx = -dx;
574                                         break;
575                                 }
576                                 Tmp_at(-2, dirlet(dx, dy));
577                         }
578                 }
579         }
580         Tmp_at(-1, -1);
581 }
582
583 static int
584 zhit(struct monst *mon, int type)       /* returns damage to mon */
585 {
586         int tmp = 0;
587
588         switch (type) {
589         case 0:         /* magic missile */
590                 tmp = d(2, 6);
591                 break;
592         case -1:        /* Dragon blazing fire */
593         case 1:         /* fire */
594                 if (strchr("Dg", mon->data->mlet))
595                         break;
596                 tmp = d(6, 6);
597                 if (strchr("YF", mon->data->mlet))
598                         tmp += 7;
599                 break;
600         case 2:         /* sleep*/
601                 mon->mfroz = 1;
602                 break;
603         case 3:         /* cold */
604                 if (strchr("YFgf", mon->data->mlet))
605                         break;
606                 tmp = d(6, 6);
607                 if (mon->data->mlet == 'D')
608                         tmp += 7;
609                 break;
610         case 4:         /* death*/
611                 if (strchr(UNDEAD, mon->data->mlet))
612                         break;
613                 tmp = mon->mhp + 1;
614                 break;
615         }
616         mon->mhp -= tmp;
617         return (tmp);
618 }
619
620 #define CORPSE_I_TO_C(otyp)     (char) ((otyp >= DEAD_ACID_BLOB)\
621                      ?  'a' + (otyp - DEAD_ACID_BLOB)\
622                      :  '@' + (otyp - DEAD_HUMAN))
623 static bool
624 revive(struct obj *obj)
625 {
626         struct monst *mtmp = NULL;
627
628         if (obj->olet == FOOD_SYM && obj->otyp > CORPSE) {
629                 /* do not (yet) revive shopkeepers */
630                 /* Note: this might conceivably produce two monsters
631                  *      at the same position - strange, but harmless */
632                 mtmp = mkmon_at(CORPSE_I_TO_C(obj->otyp), obj->ox, obj->oy);
633                 delobj(obj);
634         }
635         return (!!mtmp);        /* TRUE if some monster created */
636 }
637
638 static void
639 rloco(struct obj *obj)
640 {
641         int tx, ty, otx, oty;
642
643         otx = obj->ox;
644         oty = obj->oy;
645         do {
646                 tx = rn1(COLNO - 3, 2);
647                 ty = rn2(ROWNO);
648         } while (!goodpos(tx, ty));
649         obj->ox = tx;
650         obj->oy = ty;
651         if (cansee(otx, oty))
652                 newsym(otx, oty);
653 }
654
655 /* fractured by pick-axe or wand of striking */
656 /* no texts here! */
657 void
658 fracture_rock(struct obj *obj)
659 {
660         obj->otyp = ROCK;
661         obj->quan = 7 + rn2(60);
662         obj->owt = weight(obj);
663         obj->olet = WEAPON_SYM;
664         if (cansee(obj->ox, obj->oy))
665                 prl(obj->ox, obj->oy);
666 }
667
668 static void
669 burn_scrolls(void)
670 {
671         struct obj *obj, *obj2;
672         int cnt = 0;
673
674         for (obj = invent; obj; obj = obj2) {
675                 obj2 = obj->nobj;
676                 if (obj->olet == SCROLL_SYM) {
677                         cnt++;
678                         useup(obj);
679                 }
680         }
681         if (cnt > 1) {
682                 pline("Your scrolls catch fire!");
683                 losehp(cnt, "burning scrolls");
684         } else if (cnt) {
685                 pline("Your scroll catches fire!");
686                 losehp(1, "burning scroll");
687         }
688 }