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