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