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