hammer(8): adjust markup & improve wording
[dragonfly.git] / games / hack / hack.trap.c
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 }