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