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