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