/* steed.c */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1998. */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"

#ifdef YEOMAN

/* Monsters that might be ridden */
/* These choices have been confirmed by the folks in r.g.r.n */
static NEARDATA const char steeds[] = {
	S_QUADRUPED, S_UNICORN, S_ANGEL, S_CENTAUR, S_DRAGON, S_JABBERWOCK, '\0'
};


/* Start riding, with the given monster and saddle */
boolean
mount_steed (mon, sobj, force)
	struct monst *mon;	/* The animal */
	struct obj *sobj;	/* The saddle */
	boolean force;		/* Quietly force this animal */
{
	char buf[BUFSZ];
	struct permonst *ptr;


	/* Sanity checks */
	if (!sobj) {
		impossible("no saddle?");
		return (FALSE);
	}
	if (u.usteed) {
		if (!force)
			You("are already riding %s.", mon_nam(u.usteed));
		return (FALSE);
	}
	if (usaddle) {
		impossible("already saddled to nothing?");
		return (FALSE);
	}

	/* Is the player in the right form? */
/*	if (u.ulevel < ((Role_if(PM_KNIGHT) || Role_if(PM_YEOMAN)) ? 5 : 10)) {
		if (!force)
			You("aren't experienced enough yet.");
		return (FALSE);
	}*/
	if (Upolyd && (!humanoid(uasmon) || verysmall(uasmon) ||
			bigmonst(uasmon))) {
		if (!force)
			You("won't fit on the saddle.");
		return (FALSE);
	}
	if(!force && (near_capacity() > SLT_ENCUMBER)) {
		You_cant("do that while carrying so much stuff.");
		return (FALSE);
	}

	/* Can the player reach and see the monster? */
	if (u.uswallow || u.ustuck || u.utrap || Punished) {
	    if (!force)
		You("are stuck here for now.");
	    return (FALSE);
	}
	if (!mon || (!force && ((Blind && !Blind_telepat) ||
	    mon->mundetected ||
	    mon->m_ap_type == M_AP_FURNITURE ||
	    mon->m_ap_type == M_AP_OBJECT))) {
		if (!force)
			pline("I see nobody there.");
		return (FALSE);
	}

	/* Is this a valid monster? */
	ptr = mon->data;
	if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) {
		if (!force)
			pline("Shame on you!");
		exercise(A_WIS, FALSE);
		return (FALSE);
	}
	if (touch_petrifies(ptr) && !Stone_resistance) {
		You("touch %s.", mon_nam(mon));
 	    if (!(poly_when_stoned(uasmon) && polymon(PM_STONE_GOLEM))) {
			You("turn to stone...");
			Sprintf(buf, "attempting to ride %s", a_monnam(mon));
			killer_format = KILLED_BY;
			killer = buf;
			done(STONING);
 	    }
	}
	if (!mon->mtame || mon->isminion) {
		if (!force)
			pline("I think %s would mind.", mon_nam(mon));
		return (FALSE);
	}

	/* Lose some tameness if you're not very good */
#ifdef WEAPON_SKILLS
	if (skill_bonus(P_RIDING) <= 0) --mon->mtame;
	else if(rn2(skill_bonus(P_RIDING)) && mon->mtame < 15) ++mon->mtame;
#endif /* WEAPON_SKILLS */
	
	if (!force && !Role_if(PM_KNIGHT) && !Role_if(PM_YEOMAN) && !(mon->mtame)) {
		pline("%s resists!", Monnam(mon));
		return (FALSE);
	}
	if (!index(steeds, ptr->mlet) || (ptr->msize < MZ_MEDIUM) ||
			amorphous(ptr) || noncorporeal(ptr) ||
			is_whirly(ptr) || unsolid(ptr)) {
		if (!force)
			You_cant("ride such a creature.");
		return (FALSE);
	}

	/* Is the player impaired? */
	if (!force && Underwater && !is_swimmer(ptr)) {
		You_cant("ride that creature while under water.");
		return (FALSE);
	}
	if (!force && (Confusion || Fumbling || Glib || Wounded_legs ||
			sobj->cursed || (chance_steed() < rn2(100)))) {
		You("slip while trying to get on %s.", a_monnam(mon));
		Sprintf(buf, "slipped while mounting %s", a_monnam(mon));
		losehp(rn1(5,10), buf, NO_KILLER_PREFIX);
#ifdef WEAPON_SKILLS
		use_skill(P_RIDING, 5);
#endif
		return (FALSE);
	}

	/* Success */
	if (!force)
		You("mount %s.", mon_nam(mon));
	u.usteed = mon;
	setworn(sobj, W_SADDLE);
	/*sobj->leashmon = mon->m_id;*/
	remove_monster(mon->mx, mon->my);
	teleds(mon->mx, mon->my);

#ifdef WEAPON_SKILLS
	use_skill(P_RIDING, 10);
#endif
	return (TRUE);
}


/* Percent chance for successful actions with our steed */
int
chance_steed ()
{
	int chance = 30 + ACURR(A_DEX) + ACURR(A_CHA)/3;
	register const char *s;

	if (u.usteed) {
		chance += 2 * u.usteed->mtame;
		if (u.usteed->data == &mons[PM_PEGASUS])
			chance += 50;
	}

	/* Knights and Yeomen are natural riders */
	if (Role_if(PM_KNIGHT) || Role_if(PM_YEOMAN))
		chance += 20;

	/* Bonus for wearing "riding" gloves/boots (but not fumbling) */
	if (uarmg && uarmg->otyp != GAUNTLETS_OF_FUMBLING &&
		(s = OBJ_DESCR(objects[uarmg->otyp])) != 0 &&
		!strncmp(s, "riding ", 7)) chance += (uarmg->spe + 1) * 3;
	if (uarmf && uarmf->otyp != FUMBLE_BOOTS &&
		(s = OBJ_DESCR(objects[uarmf->otyp])) != 0 &&
		!strncmp(s, "riding ", 7)) chance += (uarmg->spe + 1) * 3;

#ifdef WEAPON_SKILLS
	chance += skill_bonus(P_RIDING) * 10;
#endif
#ifdef DEBUG
	pline("Ride Chance: %i", chance);
#endif
	return (chance);
}


/* Are we still allowed to ride? */
void
check_steed ()
{
	char buf[BUFSZ];
	struct permonst *ptr;


	if (!u.usteed)
		return;

	ptr = u.usteed->data;
	if (touch_petrifies(ptr) && !Stone_resistance) {
		You("touch %s.", mon_nam(u.usteed));
 	    if (!(poly_when_stoned(uasmon) && polymon(PM_STONE_GOLEM))) {
			You("turn to stone...");
			Sprintf(buf, "riding %s", a_monnam(u.usteed));
			killer_format = KILLED_BY;
			killer = buf;
			done(STONING);
 	    }
	}

	if ((Upolyd && (!humanoid(uasmon) || verysmall(uasmon) ||
			bigmonst(uasmon))) || !u.usteed->mtame ||
			!index(steeds, ptr->mlet) || (ptr->msize < MZ_MEDIUM) ||
			amorphous(ptr) || noncorporeal(ptr) ||
			is_whirly(ptr) || unsolid(ptr) ||
			(Underwater && !is_swimmer(ptr)))
		dismount_steed(TRUE);
	return;
}


/* You and your steed have moved */
void
exercise_steed ()
{
	if (!u.usteed || !usaddle)
		return;

#ifdef WEAPON_SKILLS
	/* It takes many turns of riding to exercise skill */
	/* We store this number in the saddle */
	if (usaddle->age++ >= 100L) {
		usaddle->age = 0L;
		use_skill(P_RIDING, 1);
	}
#endif
	return;
}


/* The player kicks or whips the steed */
void
kick_steed ()
{
	if (!u.usteed)
		return;

	/* Make the steed less tame and check if it resists */
#ifdef WEAPON_SKILLS
	if (skill_bonus(P_RIDING) <= 0) --u.usteed->mtame;
	else if(rn2(skill_bonus(P_RIDING)) && u.usteed->mtame < 15) ++u.usteed->mtame;
#endif /* WEAPON_SKILLS */
	
	if (!u.usteed->mtame || chance_steed() < rn2(100)) {
		dismount_steed(TRUE);
		return;
	}

	/* Possible effects */
	switch (rn2(2)) {
		case 1:
			pline("%s leaps!", Monnam(u.usteed));
			jump(u.ulevel/4);
			break;
		default:
			pline("%s gallops!", Monnam(u.usteed));
			incr_itimeout(&HFast, rn1(20, 30));
			EFast |= W_SADDLE;
			break;
	}
#ifdef WEAPON_SKILLS
	use_skill(P_RIDING, 1);
#endif
	return;
}


/* Stop riding the current steed */
void
dismount_steed (fall)
	boolean fall;		/* Player was thrown off */
{
	struct monst *mon;
	coord cc;


	/* Sanity checks */
	if (!(mon = u.usteed))
		/* Just return silently */
		return;
	if (!usaddle) {
		impossible("riding without a saddle?");
		u.usteed = 0;
		return;
	}

	if (fall) {
		if (mon->mtame) mon->mtame--;
		You("are thrown off of %s!", mon_nam(mon));
		losehp(rn1(10,10), "riding accident", KILLED_BY_AN);
		HWounded_legs += rnd(5);
		EWounded_legs |= BOTH_SIDES;
	} else if (usaddle->cursed) {
		You("can't.  Your saddle seems to be cursed.");
		usaddle->bknown = TRUE;
		return;
	} else {
		You("dismount %s.", mon_nam(mon));
		/* Not your wounded legs */
		HWounded_legs = EWounded_legs = 0;
	}

	/* Stop the effects of galloping.
	 * Not exactly fair if part of the timeout came from a
	 * potion of speed.  But this is easier to code.
	 */
	if (EFast & W_SADDLE) {
		set_itimeout(&HFast, 0);
		EFast &= ~W_SADDLE;
	}

	/* Release the steed and saddle */
	u.usteed = 0;
	usaddle->leashmon = 0;
	setworn((struct obj *)0, usaddle->owornmask);

	/* Set player and steed's position.  Try moving the player first */
	place_monster(mon, u.ux, u.uy);
	if (!u.uswallow && !u.ustuck && enexto(&cc, u.ux, u.uy, &playermon)) {
		/* Drop your steed into water/lava */
		if (mon->mhp > 0 && is_pool(u.ux,u.uy) &&
				!is_flyer(mon->data) && !is_floater(mon->data) &&
				!is_clinger(mon->data)) {
			if (!Underwater)
				pline("%s falls into the %s!", Monnam(mon), surface(u.ux,u.uy));
			if (!is_swimmer(mon->data) && !amphibious(mon->data))
				killed(mon);
		}
		if (mon->mhp > 0 && is_lava(u.ux,u.uy) &&
				!is_flyer(mon->data) && !is_floater(mon->data) &&
				!is_clinger(mon->data)) {
			pline("%s is pulled into the lava!", Monnam(mon));
			if (!likes_lava(mon->data))
				killed(mon);
		}

		/* Keep steed here, move the player to cc */
		teleds(cc.x, cc.y);
		vision_full_recalc = 1;

		/* Put your steed in your trap */
		if (u.utrap && mon->mhp > 0)
			mintrap(mon);
		u.utrap = 0;
	/* Couldn't... try placing the steed */
	} else if (enexto(&cc, u.ux, u.uy, mon->data))
		/* Keep player here, move the steed to cc */
		rloc_to(mon, cc.x, cc.y);
		/* Player stays put */
	/* Otherwise, kill the steed */
	else killed(mon);

	/* Return the player to the floor */
	float_down(0L, W_SADDLE);
	flags.botl = 1;
	(void)encumber_msg();
	return;
}


#endif /* YEOMAN */
