xref: /dragonfly/games/hack/hack.do.c (revision 4318c66eac379e15105fe145d406dfef81b795f6)
1 /*        $NetBSD: hack.do.c,v 1.11 2011/08/06 20:29:37 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 /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) and 't' (throw) */
65 
66 #include <fcntl.h>
67 #include <unistd.h>
68 #include <stdlib.h>
69 #include "hack.h"
70 #include "extern.h"
71 
72 
73 static int drop(struct obj *);
74 static void dropy(struct obj *);
75 
76 int
dodrop(void)77 dodrop(void)
78 {
79           return (drop(getobj("0$#", "drop")));
80 }
81 
82 static int
drop(struct obj * obj)83 drop(struct obj *obj)
84 {
85           if (!obj)
86                     return (0);
87           if (obj->olet == '$') {       /* pseudo object */
88                     long            amount = OGOLD(obj);
89 
90                     if (amount == 0)
91                               pline("You didn't drop any gold pieces.");
92                     else {
93                               mkgold(amount, u.ux, u.uy);
94                               pline("You dropped %ld gold piece%s.",
95                                     amount, plur(amount));
96                               if (Invisible)
97                                         newsym(u.ux, u.uy);
98                     }
99                     free(obj);
100                     return (1);
101           }
102           if (obj->owornmask & (W_ARMOR | W_RING)) {
103                     pline("You cannot drop something you are wearing.");
104                     return (0);
105           }
106           if (obj == uwep) {
107                     if (uwep->cursed) {
108                               pline("Your weapon is welded to your hand!");
109                               return (0);
110                     }
111                     setuwep((struct obj *) 0);
112           }
113           pline("You dropped %s.", doname(obj));
114           dropx(obj);
115           return (1);
116 }
117 
118 /* Called in several places - should not produce texts */
119 void
dropx(struct obj * obj)120 dropx(struct obj *obj)
121 {
122           freeinv(obj);
123           dropy(obj);
124 }
125 
126 static void
dropy(struct obj * obj)127 dropy(struct obj *obj)
128 {
129           if (obj->otyp == CRYSKNIFE)
130                     obj->otyp = WORM_TOOTH;
131           obj->ox = u.ux;
132           obj->oy = u.uy;
133           obj->nobj = fobj;
134           fobj = obj;
135           if (Invisible)
136                     newsym(u.ux, u.uy);
137           subfrombill(obj);
138           stackobj(obj);
139 }
140 
141 /* drop several things */
142 int
doddrop(void)143 doddrop(void)
144 {
145           return (ggetobj("drop", drop, 0));
146 }
147 
148 int
dodown(void)149 dodown(void)
150 {
151           if (u.ux != xdnstair || u.uy != ydnstair) {
152                     pline("You can't go down here.");
153                     return (0);
154           }
155           if (u.ustuck) {
156                     pline("You are being held, and cannot go down.");
157                     return (1);
158           }
159           if (Levitation) {
160                     pline("You're floating high above the stairs.");
161                     return (0);
162           }
163           goto_level(dlevel + 1, TRUE);
164           return (1);
165 }
166 
167 int
doup(void)168 doup(void)
169 {
170           if (u.ux != xupstair || u.uy != yupstair) {
171                     pline("You can't go up here.");
172                     return (0);
173           }
174           if (u.ustuck) {
175                     pline("You are being held, and cannot go up.");
176                     return (1);
177           }
178           if (!Levitation && inv_weight() + 5 > 0) {
179                     pline("Your load is too heavy to climb the stairs.");
180                     return (1);
181           }
182           goto_level(dlevel - 1, TRUE);
183           return (1);
184 }
185 
186 void
goto_level(int newlevel,boolean at_stairs)187 goto_level(int newlevel, boolean at_stairs)
188 {
189           int fd;
190           boolean         up = (newlevel < dlevel);
191 
192           if (newlevel <= 0)
193                     done("escaped");/* in fact < 0 is impossible */
194           if (newlevel > MAXLEVEL)
195                     newlevel = MAXLEVEL;          /* strange ... */
196           if (newlevel == dlevel)
197                     return;             /* this can happen */
198 
199           glo(dlevel);
200           fd = creat(lock, FMASK);
201           if (fd < 0) {
202                     /*
203                      * This is not quite impossible: e.g., we may have
204                      * exceeded our quota. If that is the case then we
205                      * cannot leave this level, and cannot save either.
206                      * Another possibility is that the directory was not
207                      * writable.
208                      */
209                     pline("A mysterious force prevents you from going %s.",
210                           up ? "up" : "down");
211                     return;
212           }
213           if (Punished)
214                     unplacebc();
215           u.utrap = 0;                  /* needed in level_tele */
216           u.ustuck = 0;                 /* idem */
217           keepdogs();
218           seeoff(1);
219           if (u.uswallow)               /* idem */
220                     u.uswldtim = u.uswallow = 0;
221           flags.nscrinh = 1;
222           u.ux = FAR;                   /* hack */
223           (void) inshop();    /* probably was a trapdoor */
224 
225           savelev(fd, dlevel);
226           (void) close(fd);
227 
228           dlevel = newlevel;
229           if (maxdlevel < dlevel)
230                     maxdlevel = dlevel;
231           glo(dlevel);
232 
233           if (!level_exists[dlevel])
234                     mklev();
235           else {
236                     if ((fd = open(lock, O_RDONLY)) < 0) {
237                               pline("Cannot open %s .", lock);
238                               pline("Probably someone removed it.");
239                               done("tricked");
240                     }
241                     getlev(fd, hackpid, dlevel);
242                     (void) close(fd);
243           }
244 
245           if (at_stairs) {
246                     if (up) {
247                               u.ux = xdnstair;
248                               u.uy = ydnstair;
249                               if (!u.ux) {        /* entering a maze from below? */
250                                         u.ux = xupstair;    /* this will confuse the
251                                                                        * player! */
252                                         u.uy = yupstair;
253                               }
254                               if (Punished && !Levitation) {
255                                         pline("With great effort you climb the stairs.");
256                                         placebc(1);
257                               }
258                     } else {
259                               u.ux = xupstair;
260                               u.uy = yupstair;
261                               if (inv_weight() + 5 > 0 || Punished) {
262                                         pline("You fall down the stairs.");     /* %% */
263                                         losehp(rnd(3), "fall");
264                                         if (Punished) {
265                                                   if (uwep != uball && rn2(3)) {
266                                                             pline("... and are hit by the iron ball.");
267                                                             losehp(rnd(20), "iron ball");
268                                                   }
269                                                   placebc(1);
270                                         }
271                                         selftouch("Falling, you");
272                               }
273                     }
274                     {
275                               struct monst   *mtmp = m_at(u.ux, u.uy);
276                               if (mtmp)
277                                         mnexto(mtmp);
278                     }
279           } else {            /* trapdoor or level_tele */
280                     do {
281                               u.ux = rnd(COLNO - 1);
282                               u.uy = rn2(ROWNO);
283                     } while (levl[u.ux][u.uy].typ != ROOM ||
284                                m_at(u.ux, u.uy));
285                     if (Punished) {
286                               if (uwep != uball && !up /* %% */ && rn2(5)) {
287                                         pline("The iron ball falls on your head.");
288                                         losehp(rnd(25), "iron ball");
289                               }
290                               placebc(1);
291                     }
292                     selftouch("Falling, you");
293           }
294           (void) inshop();
295           initrack();
296 
297           losedogs();
298           {
299                     struct monst   *mtmp;
300                     if ((mtmp = m_at(u.ux, u.uy)) != NULL)
301                               mnexto(mtmp);       /* riv05!a3 */
302           }
303           flags.nscrinh = 0;
304           setsee();
305           seeobjs();                    /* make old cadavers disappear - riv05!a3 */
306           docrt();
307           pickup(1);
308           read_engr_at(u.ux, u.uy);
309 }
310 
311 int
donull(void)312 donull(void)
313 {
314           return (1);                   /* Do nothing, but let other things happen */
315 }
316 
317 int
dopray(void)318 dopray(void)
319 {
320           nomovemsg = "You finished your prayer.";
321           nomul(-3);
322           return (1);
323 }
324 
325 int
dothrow(void)326 dothrow(void)
327 {
328           struct obj     *obj;
329           struct monst   *mon;
330           int tmp;
331 
332           obj = getobj("#)", "throw");  /* it is also possible to throw food */
333           /* (or jewels, or iron balls ... ) */
334           if (!obj || !getdir(1))       /* ask "in what direction?" */
335                     return (0);
336           if (obj->owornmask & (W_ARMOR | W_RING)) {
337                     pline("You can't throw something you are wearing.");
338                     return (0);
339           }
340           u_wipe_engr(2);
341 
342           if (obj == uwep) {
343                     if (obj->cursed) {
344                               pline("Your weapon is welded to your hand.");
345                               return (1);
346                     }
347                     if (obj->quan > 1)
348                               setuwep(splitobj(obj, 1));
349                     else
350                               setuwep((struct obj *) 0);
351           } else if (obj->quan > 1)
352                     (void) splitobj(obj, 1);
353           freeinv(obj);
354           if (u.uswallow) {
355                     mon = u.ustuck;
356                     bhitpos.x = mon->mx;
357                     bhitpos.y = mon->my;
358           } else if (u.dz) {
359                     if (u.dz < 0) {
360                               pline("%s hits the ceiling, then falls back on top of your head.",
361                                     Doname(obj)); /* note: obj->quan == 1 */
362                               if (obj->olet == POTION_SYM)
363                                         potionhit(&youmonst, obj);
364                               else {
365                                         if (uarmh)
366                                                   pline("Fortunately, you are wearing a helmet!");
367                                         losehp(uarmh ? 1 : rnd((int) (obj->owt)), "falling object");
368                                         dropy(obj);
369                               }
370                     } else {
371                               pline("%s hits the floor.", Doname(obj));
372                               if (obj->otyp == EXPENSIVE_CAMERA) {
373                                         pline("It is shattered in a thousand pieces!");
374                                         obfree(obj, Null(obj));
375                               } else if (obj->otyp == EGG) {
376                                         pline("\"Splash!\"");
377                                         obfree(obj, Null(obj));
378                               } else if (obj->olet == POTION_SYM) {
379                                         pline("The flask breaks, and you smell a peculiar odor ...");
380                                         potionbreathe(obj);
381                                         obfree(obj, Null(obj));
382                               } else {
383                                         dropy(obj);
384                               }
385                     }
386                     return (1);
387           } else if (obj->otyp == BOOMERANG) {
388                     mon = boomhit(u.dx, u.dy);
389                     if (mon == &youmonst) {       /* the thing was caught */
390                               (void) addinv(obj);
391                               return (1);
392                     }
393           } else {
394                     if (obj->otyp == PICK_AXE && shkcatch(obj))
395                               return (1);
396 
397                     mon = bhit(u.dx, u.dy, (obj->otyp == ICE_BOX) ? 1 :
398                               (!Punished || obj != uball) ? 8 : !u.ustuck ? 5 : 1,
399                                  obj->olet,
400                                  (void (*)(struct monst *, struct obj *)) 0,
401                                  (int (*)(struct obj *, struct obj *)) 0, obj);
402           }
403           if (mon) {
404                     /* awake monster if sleeping */
405                     wakeup(mon);
406 
407                     if (obj->olet == WEAPON_SYM) {
408                               tmp = -1 + u.ulevel + mon->data->ac + abon();
409                               if (obj->otyp < ROCK) {
410                                         if (!uwep ||
411                                             uwep->otyp != obj->otyp + (BOW - ARROW))
412                                                   tmp -= 4;
413                                         else {
414                                                   tmp += uwep->spe;
415                                         }
416                               } else if (obj->otyp == BOOMERANG)
417                                         tmp += 4;
418                               tmp += obj->spe;
419                               if (u.uswallow || tmp >= rnd(20)) {
420                                         if (hmon(mon, obj, 1) == TRUE) {
421                                                   /* mon still alive */
422 #ifndef NOWORM
423                                                   cutworm(mon, bhitpos.x, bhitpos.y, obj->otyp);
424 #endif    /* NOWORM */
425                                         } else
426                                                   mon = 0;
427                                         /* weapons thrown disappear sometimes */
428                                         if (obj->otyp < BOOMERANG && rn2(3)) {
429                                                   /* check bill; free */
430                                                   obfree(obj, (struct obj *) 0);
431                                                   return (1);
432                                         }
433                               } else
434                                         miss(objects[obj->otyp].oc_name, mon);
435                     } else if (obj->otyp == HEAVY_IRON_BALL) {
436                               tmp = -1 + u.ulevel + mon->data->ac + abon();
437                               if (!Punished || obj != uball)
438                                         tmp += 2;
439                               if (u.utrap)
440                                         tmp -= 2;
441                               if (u.uswallow || tmp >= rnd(20)) {
442                                         if (hmon(mon, obj, 1) == FALSE)
443                                                   mon = 0;  /* he died */
444                               } else
445                                         miss("iron ball", mon);
446                     } else if (obj->olet == POTION_SYM && u.ulevel > rn2(15)) {
447                               potionhit(mon, obj);
448                               return (1);
449                     } else {
450                               if (cansee(bhitpos.x, bhitpos.y))
451                                         pline("You miss %s.", monnam(mon));
452                               else
453                                         pline("You miss it.");
454                               if (obj->olet == FOOD_SYM && mon->data->mlet == 'd')
455                                         if (tamedog(mon, obj))
456                                                   return (1);
457                               if (obj->olet == GEM_SYM && mon->data->mlet == 'u' &&
458                                   !mon->mtame) {
459                                         if (obj->dknown && objects[obj->otyp].oc_name_known) {
460                                                   if (objects[obj->otyp].g_val > 0) {
461                                                             u.uluck += 5;
462                                                             goto valuable;
463                                                   } else {
464                                                             pline("%s is not interested in your junk.",
465                                                                   Monnam(mon));
466                                                   }
467                                         } else {  /* value unknown to @ */
468                                                   u.uluck++;
469                               valuable:
470                                                   if (u.uluck > LUCKMAX)        /* dan@ut-ngp */
471                                                             u.uluck = LUCKMAX;
472                                                   pline("%s graciously accepts your gift.",
473                                                         Monnam(mon));
474                                                   mpickobj(mon, obj);
475                                                   rloc(mon);
476                                                   return (1);
477                                         }
478                               }
479                     }
480           }
481           /* the code following might become part of dropy() */
482           if (obj->otyp == CRYSKNIFE)
483                     obj->otyp = WORM_TOOTH;
484           obj->ox = bhitpos.x;
485           obj->oy = bhitpos.y;
486           obj->nobj = fobj;
487           fobj = obj;
488           /* prevent him from throwing articles to the exit and escaping */
489           /* subfrombill(obj); */
490           stackobj(obj);
491           if (Punished && obj == uball &&
492               (bhitpos.x != u.ux || bhitpos.y != u.uy)) {
493                     freeobj(uchain);
494                     unpobj(uchain);
495                     if (u.utrap) {
496                               if (u.utraptype == TT_PIT)
497                                         pline("The ball pulls you out of the pit!");
498                               else {
499                                         long            side =
500                                         rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
501                                         pline("The ball pulls you out of the bear trap.");
502                                         pline("Your %s leg is severely damaged.",
503                                             (side == LEFT_SIDE) ? "left" : "right");
504                                         set_wounded_legs(side, 500 + rn2(1000));
505                                         losehp(2, "thrown ball");
506                               }
507                               u.utrap = 0;
508                     }
509                     unsee();
510                     uchain->nobj = fobj;
511                     fobj = uchain;
512                     u.ux = uchain->ox = bhitpos.x - u.dx;
513                     u.uy = uchain->oy = bhitpos.y - u.dy;
514                     setsee();
515                     (void) inshop();
516           }
517           if (cansee(bhitpos.x, bhitpos.y))
518                     prl(bhitpos.x, bhitpos.y);
519           return (1);
520 }
521 
522 /* split obj so that it gets size num */
523 /* remainder is put in the object structure delivered by this call */
524 struct obj     *
splitobj(struct obj * obj,int num)525 splitobj(struct obj *obj, int num)
526 {
527           struct obj     *otmp;
528           otmp = newobj(0);
529           *otmp = *obj;                 /* copies whole structure */
530           otmp->o_id = flags.ident++;
531           otmp->onamelth = 0;
532           obj->quan = num;
533           obj->owt = weight(obj);
534           otmp->quan -= num;
535           otmp->owt = weight(otmp);     /* -= obj->owt ? */
536           obj->nobj = otmp;
537           if (obj->unpaid)
538                     splitbill(obj, otmp);
539           return (otmp);
540 }
541 
542 void
more_experienced(int exp,int rexp)543 more_experienced(int exp, int rexp)
544 {
545           u.uexp += exp;
546           u.urexp += 4 * exp + rexp;
547           if (exp)
548                     flags.botl = 1;
549           if (u.urexp >= ((pl_character[0] == 'W') ? 1000 : 2000))
550                     flags.beginner = 0;
551 }
552 
553 void
set_wounded_legs(long side,int timex)554 set_wounded_legs(long side, int timex)
555 {
556           if (!Wounded_legs || (Wounded_legs & TIMEOUT))
557                     Wounded_legs |= side + timex;
558           else
559                     Wounded_legs |= side;
560 }
561 
562 void
heal_legs(void)563 heal_legs(void)
564 {
565           if (Wounded_legs) {
566                     if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
567                               pline("Your legs feel somewhat better.");
568                     else
569                               pline("Your leg feels somewhat better.");
570                     Wounded_legs = 0;
571           }
572 }
573