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