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