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