ftp.nice.ch/pub/next/games/strategic/NetHack.s.tar.gz#/NetHackSource/src/dothrow.c

This is dothrow.c in view mode; [Download] [Up]

/*	SCCS Id: @(#)dothrow.c	3.0	89/11/15
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

/* Contains code for 't' (throw) */

#include "hack.h"

static void FDECL(hitfloor, (struct obj *));
static void FDECL(gem_accept, (struct monst *, struct obj *));
static boolean NDECL(martial);
static int FDECL(throw_gold, (struct obj *));
static const char toss_objs[] = { '0', GOLD_SYM, '#', WEAPON_SYM, 0 };
#ifdef WORM
extern boolean notonhead;
#endif

int
dothrow() {
	register struct obj *obj;

	obj = getobj(toss_objs, "throw");
	/* it is also possible to throw food */
	/* (or jewels, or iron balls... ) */

	if(!obj || !getdir(1)) {       /* ask "in what direction?" */
		if(obj && obj->olet == GOLD_SYM) u.ugold += OGOLD(obj);
		return(0);
	}

	if(obj->olet == GOLD_SYM) return(throw_gold(obj));

	if(!canletgo(obj,"throw"))
		return(0);
	if(obj->otyp == BOULDER
#ifdef POLYSELF
					&& !throws_rocks(uasmon)
#endif
								) {
		pline("It's too heavy.");
		return(1);
	}
	if(!u.dx && !u.dy && !u.dz) {
		You("cannot throw an object at yourself.");
		return(0);
	}
	u_wipe_engr(2);

	if(obj == uwep) {
	    if(welded(obj)) {
		weldmsg(obj, FALSE);
		return(1);
	    }
	    if(obj->quan > 1)
		setuwep(splitobj(obj, 1));
	    else {
		setuwep((struct obj *)0);
		if (uwep) return(1); /* unwielded, died, rewielded */
	    }
	}
	else if(obj->quan > 1)
		(void) splitobj(obj, 1);
	freeinv(obj);
	return(throwit(obj));
}

static void
hitfloor(obj)
register struct obj *obj;
{
#ifdef ALTARS
	if (IS_ALTAR(levl[u.ux][u.uy].typ)) doaltarobj(obj);
	else
#endif
		pline("%s hits the floor.", Doname2(obj));
	if (breaks(obj, TRUE)) return;
	else if(obj->olet == POTION_SYM) {
		pline("The flask breaks, and you smell a peculiar odor...");
		potionbreathe(obj);
		obfree(obj, (struct obj *)0);
	} else
		dropy(obj);
}

int
throwit(obj)
register struct obj *obj;
{
	register struct monst *mon;
	register int range;

	if(u.uswallow) {
		mon = u.ustuck;
		bhitpos.x = mon->mx;
		bhitpos.y = mon->my;
	} else if(u.dz) {
	  if(u.dz < 0) {
	    pline("%s hits the ceiling, then falls back on top of your %s.",
		Doname2(obj),		/* note: obj->quan == 1 */
		body_part(HEAD));
	    if(obj->olet == POTION_SYM)
		potionhit(&youmonst, obj);
	    else {
		if(uarmh) pline("Fortunately, you are wearing a helmet!");
		losehp(uarmh ? 1 : rnd((int)(obj->owt)), "falling object",
			KILLED_BY_AN);
		if (!breaks(obj, TRUE)) dropy(obj);
	    }
	  } else hitfloor(obj);
	  return(1);

	} else if(obj->otyp == BOOMERANG) {
		mon = boomhit(u.dx, u.dy);
		if(mon == &youmonst) {		/* the thing was caught */
			(void) addinv(obj);
			return(1);
		}
	} else {
		if(shkcatch(obj))
		    return(1);

		range = (int)((ACURR(A_STR) > 18 ? 20 : ACURR(A_STR))/2 - obj->owt/4);
		if (obj == uball) {
			if (u.ustuck) range = 1;
			else if (range >= 5) range = 5;
		}
		if (range < 1) range = 1;

		if ((obj->olet == WEAPON_SYM || obj->olet == GEM_SYM) &&
		    uwep &&
		    objects[obj->otyp].w_propellor ==
			-objects[uwep->otyp].w_propellor)
				range++;
#ifdef POLYSELF
		if (obj->otyp == BOULDER) range = 20;
#endif

		mon = bhit(u.dx, u.dy, range, obj->olet,
			(int (*)()) 0, (int (*)()) 0, obj);
	}
	if(mon) {
		/* awake monster if sleeping */
		wakeup(mon);
#ifdef WORM
		if(bhitpos.x != mon->mx || bhitpos.y != mon->my)
			notonhead = TRUE;
#endif
		if(thitmonst(mon, obj)) return(1);
	}
	if(!u.uswallow)  {
		char let = obj->olet;

		/* the code following might become part of dropy() */
		if (breaks(obj, TRUE)) {
			tmp_at(-1, let);
#ifdef TEXTCOLOR
			tmp_at(-3, (int)objects[obj->otyp].oc_color);
#else
			tmp_at(-3, (int)AT_OBJ);
#endif
			tmp_at(bhitpos.x, bhitpos.y);
			tmp_at(-1, -1);
			return(1);
		}
		if(flooreffects(obj,bhitpos.x,bhitpos.y)) return(1);
#ifdef WORM
		if(obj->otyp == CRYSKNIFE)
			obj->otyp = WORM_TOOTH;
#endif
		obj->nobj = fobj;
		fobj = obj;
		place_object(obj, bhitpos.x, bhitpos.y);
		if(obj != uball && costly_spot(bhitpos.x, bhitpos.y) &&
		   !(mon && mon->isshk && bhitpos.x == mon->mx &&
		     bhitpos.y == mon->my && !(obj->unpaid)))
			sellobj(obj);
		stackobj(obj);
		if(obj == uball &&
			(bhitpos.x != u.ux || bhitpos.y != u.uy)){
			if(u.utrap){
				if(u.utraptype == TT_PIT)
					pline("The ball pulls you out of the pit!");
				else if(u.utraptype == TT_WEB)  {
					pline("The ball pulls you out of the web!");
					pline("The web is destroyed!");
					deltrap(t_at(u.ux,u.uy));
				} else {
				register long side =
					rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
				pline("The ball pulls you out of the bear trap.");
				Your("%s %s is severely damaged.",
					(side == LEFT_SIDE) ? "left" : "right",
					body_part(LEG));
				set_wounded_legs(side, 500+rn2(1000));
				losehp(2, "leg damage from being pulled out of a bear trap",
					KILLED_BY);
				}
				u.utrap = 0;
			}
			unsee();
			u.ux = bhitpos.x - u.dx;
			u.uy = bhitpos.y - u.dy;
			movobj(uchain,u.ux,u.uy);
			setsee();
			spoteffects();
		}
		if(cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x,bhitpos.y);
	}  else
		mpickobj(u.ustuck,obj);
	return(1);
}

int
thitmonst(mon, obj)
register struct monst *mon;
register struct obj   *obj;
{
	register int	tmp; /* Base chance to hit */

	/* Differences from melee weapons:
	 *
	 * Dex still gives a bonus, but strength does not.
	 * Polymorphed players lacking attacks may still throw.
	 * There's a base -2 to hit.
	 * No bonuses for fleeing or stunned targets (they don't dodge
	 *    melee blows as readily, but dodging arrows is hard anyway).
	 * Not affected by traps, etc...
	 * Certain items which don't in themselves do damage ignore tmp.
	 */
	tmp = -2 + Luck + mon->data->ac;
#ifdef POLYSELF
	if (u.umonnum >= 0) tmp += uasmon->mlevel;
	else
#endif
		tmp += u.ulevel;
	if(ACURR(A_DEX) < 4) tmp -= 3;
	else if(ACURR(A_DEX) < 6) tmp -= 2;
	else if(ACURR(A_DEX) < 8) tmp -= 1;
	else if(ACURR(A_DEX) > 15) tmp += (ACURR(A_DEX) - 15);

	if(mon->msleep) {
		mon->msleep = 0;
		tmp += 2;
	}
	if(!mon->mcanmove) {
		tmp += 4;
		if(!rn2(10)) {
			mon->mcanmove = 1;
			mon->mfrozen = 0;
		}
	}
	if (is_orc(mon->data) && pl_character[0]=='E') tmp++;
	if (u.uswallow && mon == u.ustuck) tmp += 1000; /* Guaranteed hit */

	if(obj->olet == GEM_SYM && mon->data->mlet == S_UNICORN) {
		if (mon->mtame)
			kludge("%s catches and drops the %s.",
				Monnam(mon), xname(obj));
		else {
			kludge("%s catches the %s.", Monnam(mon), xname(obj));
			gem_accept(mon, obj);
		}
		return(1);
	}
	if(obj->olet == WEAPON_SYM || obj->otyp == PICK_AXE ||
	   obj->otyp == UNICORN_HORN || obj->olet == GEM_SYM) {
		if(obj->otyp < DART || obj->olet == GEM_SYM) {
		    if (!uwep ||
			objects[obj->otyp].w_propellor !=
			-objects[uwep->otyp].w_propellor)
			    tmp -= 4;
		    else    tmp += uwep->spe;
		} else if(obj->otyp == BOOMERANG) tmp += 4;
		tmp += obj->spe;
		tmp += hitval(obj, mon->data);
		if(tmp >= rnd(20)) {
			if(hmon(mon,obj,1) == TRUE){
			  /* mon still alive */
#ifdef WORM
			  cutworm(mon,bhitpos.x,bhitpos.y,obj->otyp);
#endif
			} else mon = 0;
			/* projectiles thrown disappear sometimes */
			if((obj->otyp < BOOMERANG || obj->olet == GEM_SYM)
								&& rn2(3)) {
				/* check bill; free */
				obfree(obj, (struct obj *)0);
				return(1);
			}
		} else miss(xname(obj), mon);
	} else if(obj->otyp == HEAVY_IRON_BALL) {
		if(obj != uball) tmp += 2;
		if(tmp >= rnd(20)) {
			if(hmon(mon,obj,1) == FALSE)
				mon = 0;	/* he died */
		} else miss(xname(obj), mon);
	} else if (obj->otyp == BOULDER) {
		tmp += 6;  /* Likely to hit! */
		if(tmp >= rnd(20)) {
			if(hmon(mon,obj,1) == FALSE)
				mon = 0;	/* he died */
		} else miss(xname(obj), mon);
	} else if((obj->otyp == CREAM_PIE
#ifdef POLYSELF
			|| obj->otyp == BLINDING_VENOM
#endif
					) && ACURR(A_DEX) >= rnd(10)) {
		(void) hmon(mon,obj,1); /* can't die from it */
#ifdef POLYSELF
	} else if(obj->otyp == ACID_VENOM && ACURR(A_DEX) >= rnd(10)) {
		if(hmon(mon,obj,1) == FALSE)
			mon = 0;
#endif
	} else if(obj->olet == POTION_SYM && ACURR(A_DEX) >= rnd(15)) {
		potionhit(mon, obj);
		return(1);
	} else {
		pline("The %s misses %s.", xname(obj),
			cansee(bhitpos.x,bhitpos.y) ? mon_nam(mon) : "it");
		if(obj->olet == FOOD_SYM && is_domestic(mon->data))
			if(tamedog(mon,obj)) return(1);
	}
	return(0);
}

static void
gem_accept(mon, obj)
register struct monst *mon;
register struct obj *obj;
{
	char buf[BUFSZ];
	static const char nogood[] = " is not interested in your junk.";
	static const char maybeluck[] = " hesitatingly accepts your gift.";
	static const char addluck[] = " graciously accepts your gift.";

	Strcpy(buf,Monnam(mon));

	mon->mpeaceful = 1;
	if(obj->dknown && objects[obj->otyp].oc_name_known)  {
		if(objects[obj->otyp].g_val > 0)  {
		    if(mon->data == &mons[
				((u.ualigntyp== U_CHAOTIC) ? PM_BLACK_UNICORN :
				 (u.ualigntyp == U_LAWFUL) ? PM_WHITE_UNICORN
						  : PM_GRAY_UNICORN)]) {
			    Strcat(buf, addluck);
			    change_luck(5);
		    } else {
			    Strcat(buf, maybeluck);
			    change_luck(rn2(7)-3);
		    }
		} else {
		    Strcat(buf,nogood);
		    goto nopick;
		}
	}  else  {  /* value unknown to @ */
		change_luck(1);
		Strcat(buf,addluck);
	}
	mpickobj(mon, obj);
nopick:
	if(!Blind) pline(buf);
	rloc(mon);
}

/* returns 0 if object doesn't break	*/
/* returns 1 if object broke 		*/
int
breaks(obj, loose)
register struct obj   *obj;
register boolean loose;		/* if not loose, obj is in fobj chain */
{
	switch(obj->otyp) {
#ifdef MEDUSA
		case MIRROR:
			change_luck(-2);	/* and fall through */
#endif
		case EXPENSIVE_CAMERA:
		case CRYSTAL_BALL:
			if(!Blind)
			    pline("%s shatters into a thousand pieces!",
				Doname2(obj));
			else You("hear something shatter!");
			break;
		case EGG:
			pline("Splat!");
			break;
		case CREAM_PIE:
			pline("What a mess!");
			break;
		case ACID_VENOM:
		case BLINDING_VENOM:
			pline("Splash!");
			break;
		default:
			return 0;
	}

	if(loose) {
		unpobj(obj);
		obfree(obj, (struct obj *)0);
	} else {
		addtobill(obj, FALSE);
		delobj(obj);
	}
	return(1);
}

static boolean 
martial() 
{
	return((pl_character[0] == 'S' || pl_character[0] == 'P'));
}

static int
throw_gold(obj)
struct obj *obj;
{
	int range = 0, odx, ody;
	long zorks = OGOLD(obj);
	register struct monst *mon;

	free((genericptr_t) obj);
	if(zorks < 0) {
		/* watch negative overflows a la drop() */
		u.ugold += zorks;
	pline("The LRS would be very interested to know you have that much.");
		return(0);
	}

	if(u.uswallow) {
		if (is_animal(u.ustuck->data))
			pline("The gold disappears in the %s's entrails.", 
			      mon_nam(u.ustuck));
		else
			pline("The gold disappears into %s.",
			      mon_nam(u.ustuck));
		u.ustuck->mgold += zorks;
		return(1);
	}

	if(u.dz) {
	  	if(u.dz < 0) {
	    pline("The gold hits the ceiling, then falls back on top of your %s.",
		    body_part(HEAD));
		    /* some self damage? */
		    if(uarmh) pline("Fortunately, you are wearing a helmet!");
		} else pline("The gold hits the floor.");
		bhitpos.x = u.ux; /* a msg is needed here */
		bhitpos.y = u.uy;
		goto skip;
	}

	range = rnd((int)ACURR(A_STR));
	if(martial()) range = range + rnd(3);

	/* see if the gold has a place to move into */
	odx = u.ux + u.dx;
	ody = u.uy + u.dy;
	if(bad_kick_throw_pos(odx,ody)) {
		bhitpos.x = u.ux;
		bhitpos.y = u.uy;
	} else {
		if (mon = ghit(u.dx, u.dy, range))
		    if (ghitm(mon, zorks))	/* was it caught? */
			zorks = 0;
	}
skip:
	if (zorks)	/* perhaps it was caught */
	    mkgold(zorks, bhitpos.x, bhitpos.y);
	if(cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x,bhitpos.y);
	return(1);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.