xref: /netbsd/games/hack/hack.trap.c (revision 759cbe51)
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