1 /*        $NetBSD: hack.trap.c,v 1.10 2011/08/07 06:03:45 dholland Exp $        */
2 
3 /*
4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5  * Amsterdam
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * - Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * - Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * - Neither the name of the Stichting Centrum voor Wiskunde en
20  * Informatica, nor the names of its contributors may be used to endorse or
21  * promote products derived from this software without specific prior
22  * written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39  * All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. The name of the author may not be used to endorse or promote products
50  *    derived from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #include <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.trap.c,v 1.10 2011/08/07 06:03:45 dholland Exp $");
67 #endif                                  /* not lint */
68 
69 #include <stdlib.h>
70 #include "hack.h"
71 #include "extern.h"
72 #include "def.mkroom.h"
73 
74 const char            vowels[] = "aeiou";
75 
76 const char           *const traps[] = {
77           " bear trap",
78           "n arrow trap",
79           " dart trap",
80           " trapdoor",
81           " teleportation trap",
82           " pit",
83           " sleeping gas trap",
84           " piercer",
85           " mimic"
86 };
87 
88 static void vtele(void);
89 static void teleds(int, int);
90 static int teleok(int, int);
91 
92 struct trap    *
maketrap(int x,int y,int typ)93 maketrap(int x, int y, int typ)
94 {
95           struct trap    *ttmp;
96 
97           ttmp = newtrap();
98           ttmp->ttyp = typ;
99           ttmp->tseen = 0;
100           ttmp->once = 0;
101           ttmp->tx = x;
102           ttmp->ty = y;
103           ttmp->ntrap = ftrap;
104           ftrap = ttmp;
105           return (ttmp);
106 }
107 
108 void
dotrap(struct trap * trap)109 dotrap(struct trap *trap)
110 {
111           int             ttype = trap->ttyp;
112 
113           nomul(0);
114           if (trap->tseen && !rn2(5) && ttype != PIT)
115                     pline("You escape a%s.", traps[ttype]);
116           else {
117                     trap->tseen = 1;
118                     switch (ttype) {
119                     case SLP_GAS_TRAP:
120                               pline("A cloud of gas puts you to sleep!");
121                               nomul(-rnd(25));
122                               break;
123                     case BEAR_TRAP:
124                               if (Levitation) {
125                                         pline("You float over a bear trap.");
126                                         break;
127                               }
128                               u.utrap = 4 + rn2(4);
129                               u.utraptype = TT_BEARTRAP;
130                               pline("A bear trap closes on your foot!");
131                               break;
132                     case PIERC:
133                               deltrap(trap);
134                               if (makemon(PM_PIERCER, u.ux, u.uy)) {
135                                         pline("A piercer suddenly drops from the ceiling!");
136                                         if (uarmh)
137                                                   pline("Its blow glances off your helmet.");
138                                         else
139                                                   (void) thitu(3, d(4, 6), "falling piercer");
140                               }
141                               break;
142                     case ARROW_TRAP:
143                               pline("An arrow shoots out at you!");
144                               if (!thitu(8, rnd(6), "arrow")) {
145                                         mksobj_at(ARROW, u.ux, u.uy);
146                                         fobj->quan = 1;
147                               }
148                               break;
149                     case TRAPDOOR:
150                               if (!xdnstair) {
151                                         pline("A trap door in the ceiling opens and a rock falls on your head!");
152                                         if (uarmh)
153                                                   pline("Fortunately, you are wearing a helmet!");
154                                         losehp(uarmh ? 2 : d(2, 10), "falling rock");
155                                         mksobj_at(ROCK, u.ux, u.uy);
156                                         fobj->quan = 1;
157                                         stackobj(fobj);
158                                         if (Invisible)
159                                                   newsym(u.ux, u.uy);
160                               } else {
161                                         int             newlevel = dlevel + 1;
162                                         while (!rn2(4) && newlevel < 29)
163                                                   newlevel++;
164                                         pline("A trap door opens up under you!");
165                                         if (Levitation || u.ustuck) {
166                                                   pline("For some reason you don't fall in.");
167                                                   break;
168                                         }
169                                         goto_level(newlevel, FALSE);
170                               }
171                               break;
172                     case DART_TRAP:
173                               pline("A little dart shoots out at you!");
174                               if (thitu(7, rnd(3), "little dart")) {
175                                         if (!rn2(6))
176                                                   poisoned("dart", "poison dart");
177                               } else {
178                                         mksobj_at(DART, u.ux, u.uy);
179                                         fobj->quan = 1;
180                               }
181                               break;
182                     case TELEP_TRAP:
183                               if (trap->once) {
184                                         deltrap(trap);
185                                         newsym(u.ux, u.uy);
186                                         vtele();
187                               } else {
188                                         newsym(u.ux, u.uy);
189                                         tele();
190                               }
191                               break;
192                     case PIT:
193                               if (Levitation) {
194                                         pline("A pit opens up under you!");
195                                         pline("You don't fall in!");
196                                         break;
197                               }
198                               pline("You fall into a pit!");
199                               u.utrap = rn1(6, 2);
200                               u.utraptype = TT_PIT;
201                               losehp(rnd(6), "fall into a pit");
202                               selftouch("Falling, you");
203                               break;
204                     default:
205                               impossible("You hit a trap of type %u", trap->ttyp);
206                     }
207           }
208 }
209 
210 int
mintrap(struct monst * mtmp)211 mintrap(struct monst *mtmp)
212 {
213           struct trap    *trap = t_at(mtmp->mx, mtmp->my);
214           int             wasintrap = mtmp->mtrapped;
215 
216           if (!trap) {
217                     mtmp->mtrapped = 0; /* perhaps teleported? */
218           } else if (wasintrap) {
219                     if (!rn2(40))
220                               mtmp->mtrapped = 0;
221           } else {
222                     int             tt = trap->ttyp;
223                     int             in_sight = cansee(mtmp->mx, mtmp->my);
224 
225                     if (mtmp->mtrapseen & (1 << tt)) {
226                               /* he has been in such a trap - perhaps he escapes */
227                               if (rn2(4))
228                                         return (0);
229                     }
230                     mtmp->mtrapseen |= (1 << tt);
231                     switch (tt) {
232                     case BEAR_TRAP:
233                               if (strchr(mlarge, mtmp->data->mlet)) {
234                                         if (in_sight)
235                                                   pline("%s is caught in a bear trap!",
236                                                         Monnam(mtmp));
237                                         else if (mtmp->data->mlet == 'o')
238                                                   pline("You hear the roaring of an angry bear!");
239                                         mtmp->mtrapped = 1;
240                               }
241                               break;
242                     case PIT:
243                               /* there should be a mtmp/data -> floating */
244                               if (!strchr("EywBfk'& ", mtmp->data->mlet)) {     /* ab */
245                                         mtmp->mtrapped = 1;
246                                         if (in_sight)
247                                                   pline("%s falls in a pit!", Monnam(mtmp));
248                               }
249                               break;
250                     case SLP_GAS_TRAP:
251                               if (!mtmp->msleep && !mtmp->mfroz) {
252                                         mtmp->msleep = 1;
253                                         if (in_sight)
254                                                   pline("%s suddenly falls asleep!",
255                                                         Monnam(mtmp));
256                               }
257                               break;
258                     case TELEP_TRAP:
259                               rloc(mtmp);
260                               if (in_sight && !cansee(mtmp->mx, mtmp->my))
261                                         pline("%s suddenly disappears!",
262                                               Monnam(mtmp));
263                               break;
264                     case ARROW_TRAP:
265                               if (in_sight) {
266                                         pline("%s is hit by an arrow!",
267                                               Monnam(mtmp));
268                               }
269                               mtmp->mhp -= 3;
270                               break;
271                     case DART_TRAP:
272                               if (in_sight) {
273                                         pline("%s is hit by a dart!",
274                                               Monnam(mtmp));
275                               }
276                               mtmp->mhp -= 2;
277                               /* not mondied here !! */
278                               break;
279                     case TRAPDOOR:
280                               if (!xdnstair) {
281                                         mtmp->mhp -= 10;
282                                         if (in_sight)
283                                                   pline("A trap door in the ceiling opens and a rock hits %s!", monnam(mtmp));
284                                         break;
285                               }
286                               if (mtmp->data->mlet != 'w') {
287                                         fall_down(mtmp);
288                                         if (in_sight)
289                                                   pline("Suddenly, %s disappears out of sight.", monnam(mtmp));
290                                         return (2);         /* no longer on this level */
291                               }
292                               break;
293                     case PIERC:
294                               break;
295                     default:
296                               impossible("Some monster encountered a strange trap.");
297                     }
298           }
299           return (mtmp->mtrapped);
300 }
301 
302 void
selftouch(const char * arg)303 selftouch(const char *arg)
304 {
305           if (uwep && uwep->otyp == DEAD_COCKATRICE) {
306                     pline("%s touch the dead cockatrice.", arg);
307                     pline("You turn to stone.");
308                     killer = objects[uwep->otyp].oc_name;
309                     done("died");
310           }
311 }
312 
313 void
float_up(void)314 float_up(void)
315 {
316           if (u.utrap) {
317                     if (u.utraptype == TT_PIT) {
318                               u.utrap = 0;
319                               pline("You float up, out of the pit!");
320                     } else {
321                               pline("You float up, only your leg is still stuck.");
322                     }
323           } else
324                     pline("You start to float in the air!");
325 }
326 
327 void
float_down(void)328 float_down(void)
329 {
330           struct trap    *trap;
331           pline("You float gently to the ground.");
332           if ((trap = t_at(u.ux, u.uy)) != NULL)
333                     switch (trap->ttyp) {
334                     case PIERC:
335                               break;
336                     case TRAPDOOR:
337                               if (!xdnstair || u.ustuck)
338                                         break;
339                               /* FALLTHROUGH */
340                     default:
341                               dotrap(trap);
342                     }
343           pickup(1);
344 }
345 
346 static void
vtele(void)347 vtele(void)
348 {
349           struct mkroom  *croom;
350           for (croom = &rooms[0]; croom->hx >= 0; croom++)
351                     if (croom->rtype == VAULT) {
352                               int x, y;
353 
354                               x = rn2(2) ? croom->lx : croom->hx;
355                               y = rn2(2) ? croom->ly : croom->hy;
356                               if (teleok(x, y)) {
357                                         teleds(x, y);
358                                         return;
359                               }
360                     }
361           tele();
362 }
363 
364 void
tele(void)365 tele(void)
366 {
367           coord           cc;
368           int             nux, nuy;
369 
370           if (Teleport_control) {
371                     pline("To what position do you want to be teleported?");
372                     cc = getpos(1, "the desired position"); /* 1: force valid */
373                     /*
374                      * possible extensions: introduce a small error if magic
375                      * power is low; allow transfer to solid rock
376                      */
377                     if (teleok(cc.x, cc.y)) {
378                               teleds(cc.x, cc.y);
379                               return;
380                     }
381                     pline("Sorry ...");
382           }
383           do {
384                     nux = rnd(COLNO - 1);
385                     nuy = rn2(ROWNO);
386           } while (!teleok(nux, nuy));
387           teleds(nux, nuy);
388 }
389 
390 static void
teleds(int nux,int nuy)391 teleds(int nux, int nuy)
392 {
393           if (Punished)
394                     unplacebc();
395           unsee();
396           u.utrap = 0;
397           u.ustuck = 0;
398           u.ux = nux;
399           u.uy = nuy;
400           setsee();
401           if (Punished)
402                     placebc(1);
403           if (u.uswallow) {
404                     u.uswldtim = u.uswallow = 0;
405                     docrt();
406           }
407           nomul(0);
408           if (levl[nux][nuy].typ == POOL && !Levitation)
409                     drown();
410           (void) inshop();
411           pickup(1);
412           if (!Blind)
413                     read_engr_at(u.ux, u.uy);
414 }
415 
416 static int
teleok(int x,int y)417 teleok(int x, int y)
418 {                                       /* might throw him into a POOL */
419           return (isok(x, y) && !IS_ROCK(levl[x][y].typ) && !m_at(x, y) &&
420                     !sobj_at(ENORMOUS_ROCK, x, y) && !t_at(x, y)
421                     );
422           /* Note: gold is permitted (because of vaults) */
423 }
424 
425 int
dotele(void)426 dotele(void)
427 {
428           if (
429 #ifdef WIZARD
430               !wizard &&
431 #endif    /* WIZARD */
432               (!Teleportation || u.ulevel < 6 ||
433                (pl_character[0] != 'W' && u.ulevel < 10))) {
434                     pline("You are not able to teleport at will.");
435                     return (0);
436           }
437           if (u.uhunger <= 100 || u.ustr < 6) {
438                     pline("You miss the strength for a teleport spell.");
439                     return (1);
440           }
441           tele();
442           morehungry(100);
443           return (1);
444 }
445 
446 void
placebc(int attach)447 placebc(int attach)
448 {
449           if (!uchain || !uball) {
450                     impossible("Where are your chain and ball??");
451                     return;
452           }
453           uball->ox = uchain->ox = u.ux;
454           uball->oy = uchain->oy = u.uy;
455           if (attach) {
456                     uchain->nobj = fobj;
457                     fobj = uchain;
458                     if (!carried(uball)) {
459                               uball->nobj = fobj;
460                               fobj = uball;
461                     }
462           }
463 }
464 
465 void
unplacebc(void)466 unplacebc(void)
467 {
468           if (!carried(uball)) {
469                     freeobj(uball);
470                     unpobj(uball);
471           }
472           freeobj(uchain);
473           unpobj(uchain);
474 }
475 
476 void
level_tele(void)477 level_tele(void)
478 {
479           int             newlevel;
480           if (Teleport_control) {
481                     char            buf[BUFSZ];
482 
483                     do {
484                               pline("To what level do you want to teleport? [type a number] ");
485                               getlin(buf);
486                     } while (!digit(buf[0]) && (buf[0] != '-' || !digit(buf[1])));
487                     newlevel = atoi(buf);
488           } else {
489                     newlevel = 5 + rn2(20);       /* 5 - 24 */
490                     if (dlevel == newlevel) {
491                               if (!xdnstair)
492                                         newlevel--;
493                               else
494                                         newlevel++;
495                     }
496           }
497           if (newlevel >= 30) {
498                     if (newlevel > MAXLEVEL)
499                               newlevel = MAXLEVEL;
500                     pline("You arrive at the center of the earth ...");
501                     pline("Unfortunately it is here that hell is located.");
502                     if (Fire_resistance) {
503                               pline("But the fire doesn't seem to harm you.");
504                     } else {
505                               pline("You burn to a crisp.");
506                               dlevel = maxdlevel = newlevel;
507                               killer = "visit to the hell";
508                               done("burned");
509                     }
510           }
511           if (newlevel < 0) {
512                     newlevel = 0;
513                     pline("You are now high above the clouds ...");
514                     if (Levitation) {
515                               pline("You float gently down to earth.");
516                               done("escaped");
517                     }
518                     pline("Unfortunately, you don't know how to fly.");
519                     pline("You fall down a few thousand feet and break your neck.");
520                     dlevel = 0;
521                     killer = "fall";
522                     done("died");
523           }
524           goto_level(newlevel, FALSE);  /* calls done("escaped") if
525                                                    * newlevel==0 */
526 }
527 
528 void
drown(void)529 drown(void)
530 {
531           pline("You fall into a pool!");
532           pline("You can't swim!");
533           if (rn2(3) < u.uluck + 2) {
534                     /* most scrolls become unreadable */
535                     struct obj     *obj;
536 
537                     for (obj = invent; obj; obj = obj->nobj)
538                               if (obj->olet == SCROLL_SYM && rn2(12) > u.uluck)
539                                         obj->otyp = SCR_BLANK_PAPER;
540                     /* we should perhaps merge these scrolls ? */
541 
542                     pline("You attempt a teleport spell."); /* utcsri!carroll */
543                     (void) dotele();
544                     if (levl[u.ux][u.uy].typ != POOL)
545                               return;
546           }
547           pline("You drown ...");
548           killer = "pool of water";
549           done("drowned");
550 }
551