Merge branch 'vendor/OPENPAM'
[dragonfly.git] / games / hack / hack.apply.c
1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.apply.c - version 1.0.3 */
3 /* $FreeBSD: src/games/hack/hack.apply.c,v 1.4.2.1 2001/02/18 02:20:07 kris Exp $ */
4
5 #include "hack.h"
6 #include "def.edog.h"
7 extern char quitchars[];
8
9 static void              use_camera(struct obj *);
10 static bool              in_ice_box(struct obj *);
11 static bool              ck_ice_box(struct obj *);
12 static int               out_ice_box(struct obj *);
13 static void              use_ice_box(struct obj *);
14 static struct monst     *bchit(int, int, int, char);
15 static void              use_whistle(struct obj *);
16 static void              use_magic_whistle(struct obj *);
17 static bool              dig(void);
18 static int               use_pick_axe(struct obj *);
19
20 int
21 doapply(void)
22 {
23         struct obj *obj;
24         int res = 1;
25
26         obj = getobj("(", "use or apply");
27         if (!obj)
28                 return (0);
29
30         switch (obj->otyp) {
31         case EXPENSIVE_CAMERA:
32                 use_camera(obj);
33                 break;
34         case ICE_BOX:
35                 use_ice_box(obj);
36                 break;
37         case PICK_AXE:
38                 res = use_pick_axe(obj);
39                 break;
40
41         case MAGIC_WHISTLE:
42                 if (pl_character[0] == 'W' || u.ulevel > 9) {
43                         use_magic_whistle(obj);
44                         break;
45                 }
46                 /* FALLTHROUGH */
47         case WHISTLE:
48                 use_whistle(obj);
49                 break;
50
51         case CAN_OPENER:
52                 if (!carrying(TIN)) {
53                         pline("You have no can to open.");
54                         goto xit;
55                 }
56                 pline("You cannot open a tin without eating its contents.");
57                 pline("In order to eat, use the 'e' command.");
58                 if (obj != uwep)
59                         pline("Opening the tin will be much easier if you wield the can-opener.");
60                 goto xit;
61
62         default:
63                 pline("Sorry, I don't know how to use that.");
64 xit:
65                 nomul(0);
66                 return (0);
67         }
68         nomul(0);
69         return (res);
70 }
71
72 static void
73 use_camera(struct obj *obj __unused)
74 {
75         struct monst *mtmp;
76
77         if (!getdir(1)) {       /* ask: in what direction? */
78                 flags.move = multi = 0;
79                 return;
80         }
81         if (u.uswallow) {
82                 pline("You take a picture of %s's stomach.", monnam(u.ustuck));
83                 return;
84         }
85         if (u.dz) {
86                 pline("You take a picture of the %s.",
87                     (u.dz > 0) ? "floor" : "ceiling");
88                 return;
89         }
90         if ((mtmp = bchit(u.dx, u.dy, COLNO, '!')) != NULL) {
91                 if (mtmp->msleep) {
92                         mtmp->msleep = 0;
93                         pline("The flash awakens %s.", monnam(mtmp));   /* a3 */
94                 } else if (mtmp->data->mlet != 'y')
95                         if (mtmp->mcansee || mtmp->mblinded) {
96                                 int tmp = dist(mtmp->mx, mtmp->my);
97                                 int tmp2;
98                                 if (cansee(mtmp->mx, mtmp->my))
99                                         pline("%s is blinded by the flash!", Monnam(mtmp));
100                                 setmangry(mtmp);
101                                 if (tmp < 9 && !mtmp->isshk && rn2(4)) {
102                                         mtmp->mflee = 1;
103                                         if (rn2(4))
104                                                 mtmp->mfleetim = rnd(100);
105                                 }
106                                 if (tmp < 3)
107                                         mtmp->mcansee = mtmp->mblinded = 0;
108                                 else {
109                                         tmp2 = mtmp->mblinded;
110                                         tmp2 += rnd(1 + 50 / tmp);
111                                         if (tmp2 > 127)
112                                                 tmp2 = 127;
113                                         mtmp->mblinded = tmp2;
114                                         mtmp->mcansee = 0;
115                                 }
116                         }
117         }
118 }
119
120 static
121 struct obj *current_ice_box;    /* a local variable of use_ice_box, to be
122                                 used by its local procedures in/ck_ice_box */
123 static bool
124 in_ice_box(struct obj *obj)
125 {
126         if (obj == current_ice_box ||
127             (Punished && (obj == uball || obj == uchain))) {
128                 pline("You must be kidding.");
129                 return (0);
130         }
131         if (obj->owornmask & (W_ARMOR | W_RING)) {
132                 pline("You cannot refrigerate something you are wearing.");
133                 return (0);
134         }
135         if (obj->owt + current_ice_box->owt > 70) {
136                 pline("It won't fit.");
137                 return (1);     /* be careful! */
138         }
139         if (obj == uwep) {
140                 if (uwep->cursed) {
141                         pline("Your weapon is welded to your hand!");
142                         return (0);
143                 }
144                 setuwep(NULL);
145         }
146         current_ice_box->owt += obj->owt;
147         freeinv(obj);
148         obj->o_cnt_id = current_ice_box->o_id;
149         obj->nobj = fcobj;
150         fcobj = obj;
151         obj->age = moves - obj->age;    /* actual age */
152         return (1);
153 }
154
155 static bool
156 ck_ice_box(struct obj *obj)
157 {
158         return (obj->o_cnt_id == current_ice_box->o_id);
159 }
160
161 static int
162 out_ice_box(struct obj *obj)
163 {
164         struct obj *otmp;
165
166         if (obj == fcobj)
167                 fcobj = fcobj->nobj;
168         else {
169                 for (otmp = fcobj; otmp->nobj != obj; otmp = otmp->nobj)
170                         if (!otmp->nobj)
171                                 panic("out_ice_box");
172                 otmp->nobj = obj->nobj;
173         }
174         current_ice_box->owt -= obj->owt;
175         obj->age = moves - obj->age;    /* simulated point of time */
176         addinv(obj);
177         return (0);
178 }
179
180 static void
181 use_ice_box(struct obj *obj)
182 {
183         int cnt = 0;
184         struct obj *otmp;
185
186         current_ice_box = obj;  /* for use by in/out_ice_box */
187         for (otmp = fcobj; otmp; otmp = otmp->nobj)
188                 if (otmp->o_cnt_id == obj->o_id)
189                         cnt++;
190         if (!cnt)
191                 pline("Your ice-box is empty.");
192         else {
193                 pline("Do you want to take something out of the ice-box? [yn] ");
194                 if (readchar() == 'y')
195                         if (askchain(fcobj, NULL, 0, out_ice_box, ck_ice_box, 0))
196                                 return;
197                 pline("That was all. Do you wish to put something in? [yn] ");
198                 if (readchar() != 'y')
199                         return;
200         }
201         /* call getobj: 0: allow cnt; #: allow all types; %: expect food */
202         otmp = getobj("0#%", "put in");
203         if (!otmp || !in_ice_box(otmp))
204                 flags.move = multi = 0;
205 }
206
207 static
208 struct monst *
209 bchit(int ddx, int ddy, int range, char sym)
210 {
211         struct monst *mtmp = NULL;
212         int bchx = u.ux, bchy = u.uy;
213
214         if (sym)
215                 Tmp_at(-1, sym);        /* open call */
216         while (range--) {
217                 bchx += ddx;
218                 bchy += ddy;
219                 if ((mtmp = m_at(bchx, bchy)))
220                         break;
221                 if (!ZAP_POS(levl[bchx][bchy].typ)) {
222                         bchx -= ddx;
223                         bchy -= ddy;
224                         break;
225                 }
226                 if (sym)
227                         Tmp_at(bchx, bchy);
228         }
229         if (sym)
230                 Tmp_at(-1, -1);
231         return (mtmp);
232 }
233
234 static void
235 use_whistle(struct obj *obj __unused)
236 {
237         struct monst *mtmp = fmon;
238
239         pline("You produce a high whistling sound.");
240         while (mtmp) {
241                 if (dist(mtmp->mx, mtmp->my) < u.ulevel * 20) {
242                         if (mtmp->msleep)
243                                 mtmp->msleep = 0;
244                         if (mtmp->mtame)
245                                 EDOG(mtmp)->whistletime = moves;
246                 }
247                 mtmp = mtmp->nmon;
248         }
249 }
250
251 static void
252 use_magic_whistle(struct obj *obj __unused)
253 {
254         struct monst *mtmp = fmon;
255
256         pline("You produce a strange whistling sound.");
257         while (mtmp) {
258                 if (mtmp->mtame)
259                         mnexto(mtmp);
260                 mtmp = mtmp->nmon;
261         }
262 }
263
264 static int dig_effort;  /* effort expended on current pos */
265 static uchar dig_level;
266 static coord dig_pos;
267 static boolean dig_down;
268
269 static
270 bool
271 dig(void)
272 {
273         struct rm *lev;
274         int dpx = dig_pos.x, dpy = dig_pos.y;
275
276         /* perhaps a nymph stole his pick-axe while he was busy digging */
277         /* or perhaps he teleported away */
278         if (u.uswallow || !uwep || uwep->otyp != PICK_AXE ||
279             dig_level != dlevel ||
280             ((dig_down && (dpx != u.ux || dpy != u.uy)) ||
281              (!dig_down && dist(dpx, dpy) > 2)))
282                 return (0);
283
284         dig_effort += 10 + abon() + uwep->spe + rn2(5);
285         if (dig_down) {
286                 if (!xdnstair) {
287                         pline("The floor here seems too hard to dig in.");
288                         return (0);
289                 }
290                 if (dig_effort > 250) {
291                         dighole();
292                         return (0);     /* done with digging */
293                 }
294                 if (dig_effort > 50) {
295                         struct trap *ttmp = t_at(dpx, dpy);
296
297                         if (!ttmp) {
298                                 ttmp = maketrap(dpx, dpy, PIT);
299                                 ttmp->tseen = 1;
300                                 pline("You have dug a pit.");
301                                 u.utrap = rn1(4, 2);
302                                 u.utraptype = TT_PIT;
303                                 return (0);
304                         }
305                 }
306         } else if (dig_effort > 100) {
307                 const char *digtxt;
308                 struct obj *obj;
309
310                 lev = &levl[dpx][dpy];
311                 if ((obj = sobj_at(ENORMOUS_ROCK, dpx, dpy)) != NULL) {
312                         fracture_rock(obj);
313                         digtxt = "The rock falls apart.";
314                 } else if (!lev->typ || lev->typ == SCORR) {
315                         lev->typ = CORR;
316                         digtxt = "You succeeded in cutting away some rock.";
317                 } else if (lev->typ == HWALL || lev->typ == VWALL
318                     || lev->typ == SDOOR) {
319                         lev->typ = xdnstair ? DOOR : ROOM;
320                         digtxt = "You just made an opening in the wall.";
321                 } else
322                         digtxt = "Now what exactly was it that you were digging in?";
323                 mnewsym(dpx, dpy);
324                 prl(dpx, dpy);
325                 pline("%s", digtxt);    /* after mnewsym & prl */
326                 return (0);
327         } else {
328                 if (IS_WALL(levl[dpx][dpy].typ)) {
329                         int rno = inroom(dpx, dpy);
330
331                         if (rno >= 0 && rooms[rno].rtype >= 8) {
332                                 pline("This wall seems too hard to dig into.");
333                                 return (0);
334                         }
335                 }
336                 pline("You hit the rock with all your might.");
337         }
338         return (1);
339 }
340
341 /* When will hole be finished? Very rough indication used by shopkeeper. */
342 int
343 holetime(void)
344 {
345         return ((occupation == dig) ? (250 - dig_effort) / 20 : -1);
346 }
347
348 void
349 dighole(void)
350 {
351         struct trap *ttmp = t_at(u.ux, u.uy);
352
353         if (!xdnstair) {
354                 pline("The floor here seems too hard to dig in.");
355         } else {
356                 if (ttmp)
357                         ttmp->ttyp = TRAPDOOR;
358                 else
359                         ttmp = maketrap(u.ux, u.uy, TRAPDOOR);
360                 ttmp->tseen = 1;
361                 pline("You've made a hole in the floor.");
362                 if (!u.ustuck) {
363                         if (inshop())
364                                 shopdig(1);
365                         pline("You fall through ...");
366                         if (u.utraptype == TT_PIT) {
367                                 u.utrap = 0;
368                                 u.utraptype = 0;
369                         }
370                         goto_level(dlevel + 1, FALSE);
371                 }
372         }
373 }
374
375 static int
376 use_pick_axe(struct obj *obj)
377 {
378         char dirsyms[12];
379         char *dsp = dirsyms, *sdp = sdir;
380         struct monst *mtmp;
381         struct rm *lev;
382         int rx, ry, res = 0;
383
384         if (obj != uwep) {
385                 if (uwep && uwep->cursed) {
386                         /* Andreas Bormann - ihnp4!decvax!mcvax!unido!ab */
387                         pline("Since your weapon is welded to your hand,");
388                         pline("you cannot use that pick-axe.");
389                         return (0);
390                 }
391                 pline("You now wield %s.", doname(obj));
392                 setuwep(obj);
393                 res = 1;
394         }
395         while (*sdp) {
396                 movecmd(*sdp);  /* sets u.dx and u.dy and u.dz */
397                 rx = u.ux + u.dx;
398                 ry = u.uy + u.dy;
399                 if (u.dz > 0 || (u.dz == 0 && isok(rx, ry) &&
400                     (IS_ROCK(levl[rx][ry].typ)
401                     || sobj_at(ENORMOUS_ROCK, rx, ry))))
402                         *dsp++ = *sdp;
403                 sdp++;
404         }
405         *dsp = 0;
406         pline("In what direction do you want to dig? [%s] ", dirsyms);
407         if (!getdir(0))         /* no txt */
408                 return (res);
409         if (u.uswallow && attack(u.ustuck))     /* return(1) */
410                 ;
411         else if (u.dz < 0)
412                 pline("You cannot reach the ceiling.");
413         else if (u.dz == 0) {
414                 if (Confusion)
415                         confdir();
416                 rx = u.ux + u.dx;
417                 ry = u.uy + u.dy;
418                 if ((mtmp = m_at(rx, ry)) && attack(mtmp))
419                         return (1);
420                 if (!isok(rx, ry)) {
421                         pline("Clash!");
422                         return (1);
423                 }
424                 lev = &levl[rx][ry];
425                 if (lev->typ == DOOR)
426                         pline("Your %s against the door.",
427                             aobjnam(obj, "clang"));
428                 else if (!IS_ROCK(lev->typ)
429                     && !sobj_at(ENORMOUS_ROCK, rx, ry)) {
430                         /* ACCESSIBLE or POOL */
431                         pline("You swing your %s through thin air.",
432                             aobjnam(obj, NULL));
433                 } else {
434                         if (dig_pos.x != rx || dig_pos.y != ry
435                             || dig_level != dlevel || dig_down) {
436                                 dig_down = FALSE;
437                                 dig_pos.x = rx;
438                                 dig_pos.y = ry;
439                                 dig_level = dlevel;
440                                 dig_effort = 0;
441                                 pline("You start digging.");
442                         } else
443                                 pline("You continue digging.");
444                         occupation = dig;
445                         occtxt = "digging";
446                 }
447         } else if (Levitation) {
448                 pline("You cannot reach the floor.");
449         } else {
450                 if (dig_pos.x != u.ux || dig_pos.y != u.uy
451                     || dig_level != dlevel || !dig_down) {
452                         dig_down = TRUE;
453                         dig_pos.x = u.ux;
454                         dig_pos.y = u.uy;
455                         dig_level = dlevel;
456                         dig_effort = 0;
457                         pline("You start digging in the floor.");
458                         if (inshop())
459                                 shopdig(0);
460                 } else
461                         pline("You continue digging in the floor.");
462                 occupation = dig;
463                 occtxt = "digging";
464         }
465         return (1);
466 }