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