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