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