nrelease - fix/improve livecd
[dragonfly.git] / games / hack / hack.do.c
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
77 dodrop(void)
78 {
79         return (drop(getobj("0$#", "drop")));
80 }
81
82 static int
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
120 dropx(struct obj *obj)
121 {
122         freeinv(obj);
123         dropy(obj);
124 }
125
126 static void
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
143 doddrop(void)
144 {
145         return (ggetobj("drop", drop, 0));
146 }
147
148 int
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
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
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
312 donull(void)
313 {
314         return (1);             /* Do nothing, but let other things happen */
315 }
316
317 int
318 dopray(void)
319 {
320         nomovemsg = "You finished your prayer.";
321         nomul(-3);
322         return (1);
323 }
324
325 int
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     *
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
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
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
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 }