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