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