roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
/*
 * warriors.cpp
 *   Functions that deal with warrior like abilities
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "unique.h"


//*********************************************************************
//						disarmSelf
//*********************************************************************

void Player::disarmSelf() {
	bool removed = false;
	if(ready[WIELD-1] && ready[WIELD-1]->getType() == WEAPON && !ready[WIELD-1]->flagIsSet(O_CURSED)) {
		printColor("You removed %1P\n", ready[WIELD-1]);
		broadcast(getSock(),  getRoomParent(), "%M removed %1P.", this, ready[WIELD-1]);
		unequip(WIELD);
		removed = true;
	}

	if(ready[HELD-1] && ready[HELD-1]->getType() == WEAPON) {
		if(ready[HELD-1]->flagIsSet(O_CURSED)) {
			if(!ready[WIELD-1]) {
				ready[WIELD-1] = ready[HELD-1];
				ready[HELD-1] = 0;
				if(ready[WIELD-1]->flagIsSet(O_NO_PREFIX)) {
					print("%s jumped to your primary hand! It's cursed!\n", ready[WIELD-1]->getCName());
				} else {
					print("The %s jumped to your primary hand! It's cursed!\n", ready[WIELD-1]->getCName());
				}
			}
		} else {
			printColor("You removed %1P\n", ready[HELD-1]);
			broadcast(getSock(),  getRoomParent(), "%M removed %1P.", this, ready[HELD-1]);
			unequip(HELD);
			removed = true;
		}
	}
	if(removed == false)
		print("Disarm whom?\n");
	else
		unhide();
}

//*********************************************************************
//						cmdDisarm
//*********************************************************************

int cmdDisarm(Player* player, cmd* cmnd) {
	Creature* creature=0;
	Player	*pCreature=0;
	BaseRoom* room = player->getRoomParent();
	long	i=0, t=0;
	int		chance=0, drop=0;

	if(!player->ableToDoCommand())
		return(0);

	if(cmnd->num < 2) {
		player->disarmSelf();
		return(0);
	}

	if(!player->knowsSkill("disarm")) {
		player->print("You are not skilled in the art of disarming your opponents.\n");
		return(0);
	}

	creature = room->findCreature(player, cmnd->str[1], cmnd->val[1], true, true);
	if(creature)
		pCreature = creature->getAsPlayer();
	if(!creature || creature == player || (pCreature && strlen(cmnd->str[1]) < 3)) {
		player->print("They aren't here.\n");
		return(0);
	}

	if(!player->canAttack(creature))
		return(0);

	if(player->isBlind()) {
		player->printColor("^CYou're blind!\n");
		return(0);
	}

	if(!creature->ready[WIELD-1]) {
		player->print("%s isn't wielding anything to disarm!\n", creature->upHeShe());
		return(0);
	}

	if(	!player->ready[WIELD-1] &&
		!player->checkStaff("You must be wielding a weapon in order to disarm %N.\n", creature)
	)
		return(0);

	if(	player->ready[WIELD-1]->getWeaponCategory() == "ranged" &&
		!player->checkStaff("Ranged weapons may not be used to disarm.\n")
	)
		return(0);




	i = player->lasttime[LT_DISARM].ltime;
	t = time(0);

	if((t - i < 30L) && !player->isCt()) {
		player->pleaseWait(30L-t+i);
		return(0);
	}

	player->smashInvis();
	player->interruptDelayedActions();
	player->unhide();

	if(pCreature) {

	} else {
		//addEnmCrt(player, creature);
		if(player->flagIsSet(P_LAG_PROTECTION_SET)) {    // Activates lag protection.
			player->setFlag(P_LAG_PROTECTION_ACTIVE);
		}
	}


	player->updateAttackTimer(true, DEFAULT_WEAPON_DELAY);
	player->lasttime[LT_DISARM].ltime = t;
	player->lasttime[LT_DISARM].interval = 30L;
	player->lasttime[LT_KICK].ltime = t;
	player->lasttime[LT_KICK].interval = 3L;


	int level = (int)player->getSkillLevel("disarm");
	chance = 30 + (level - creature->getLevel()) * 10
			+ bonus((int) player->dexterity.getCur()) * 5;
	if(player->getClass() == ROGUE)
		chance += 10;
	chance = MIN(chance, 85);


	if(creature->ready[WIELD-1]->flagIsSet(O_CURSED))
		chance = 3;

	if(creature->flagIsSet(M_UN_DODGEABLE))
		chance /= 4;

	if(player->isDm())
		chance = 100;

	if(creature->isCt() && !player->isDm())
		chance = 0;



	if(mrand(1, 100) > chance) {
		player->print("You fail to disarm %N.\n", creature);
		player->checkImprove("disarm", false);
		creature->print("%M tried to disarm you!\n",player);
		broadcast(player->getSock(),  creature->getSock(), room, "%M attempts to disarm %N.\n", player, creature);
		if(creature->isMonster())
			creature->getAsMonster()->addEnemy(player);
		return(0);
	} else {
		if(player->getClass() == CARETAKER)
			log_immort(false,player, "%s disarms %s.\n", player->getCName(), creature->getCName());

		drop = 5 + ((level - creature->getLevel()) - (bonus((int) creature->dexterity.getCur())*2));

		player->checkImprove("disarm", true);
		if(player->isDm())
			drop = 101;

		// monsters can never be disarmed of their unique items
		if(creature->isMonster() && Unique::is(creature->ready[WIELD-1]))
			drop = 0;

		if(	mrand(1,100) <= drop &&
			!creature->ready[WIELD-1]->flagIsSet(O_NO_DROP)
		) {
			player->print("You disarm %N!\n", creature);
			player->printColor("You force %N to drop %P!\n", creature, creature->ready[WIELD-1]);
			creature->print("%M disarmed you!\n", player);

			broadcast(player->getSock(),  creature->getSock(), room, "%M attempts to disarm %N.", player, creature);
			broadcast(player->getSock(),  creature->getSock(), room, "%M dropped %s weapon!", creature, player->hisHer());
			if(creature->isPlayer())
				creature->print("You drop your weapon!\n");

			Object* toDrop = creature->unequip(WIELD, UNEQUIP_NOTHING);
			toDrop->addToRoom(room);
			creature->stun(2);
			if(creature->isPlayer())
				creature->unhide();
			if(creature->isMonster())  {
				creature->getAsMonster()->addEnemy(player);
				//		creature->setFlag(MDRWPN);
				creature->setFlag(M_GUARD_TREATURE);   // Can't pick up weapon until you kill mob that dropped it.
			}
		} else {
			player->print("You disarm %N!\n", creature);
			creature->print("%M disarmed you!\n", player);
			player->print("%s fumbles %s weapon!\n", creature->upHeShe(), creature->hisHer());
			broadcast(player->getSock(),  creature->getSock(), room, "%M attempts to disarm %N.", player, creature);
			broadcast(player->getSock(),  creature->getSock(), room, "%M fumbles %s weapon!", creature, creature->hisHer());

			if(creature->ready[HELD-1] && creature->getClass() == RANGER)
				creature->printColor("^gYou FUMBLE your primary weapon.\n");
			else
				creature->printColor("^gYou FUMBLE your weapon.\n");

			creature->unequip(WIELD);
			creature->stun(2);
			if(creature->isPlayer())
				creature->unhide();
			else
				creature->getAsMonster()->addEnemy(player);
		}
	}

	return(0);
}


//*********************************************************************
//						cmdMistbane
//*********************************************************************

int cmdMistbane(Player* player, cmd* cmnd) {
	long	i=0, t=0;
	int		chance=0;

	if(!player->ableToDoCommand())
		return(0);

	if(!player->knowsSkill("mistbane")) {
		player->print("You lack the ability to do that.\n");
		return(0);
	}
	if(player->isUndead()) {
		player->print("You cannot imbue yourself with positive energy.\n");
		return(0);
	}
	if(player->flagIsSet(P_MISTBANE)) {
		player->print("You're already empowered to hit mists.\n");
		return(0);
	}

	i = player->lasttime[LT_MISTBANE].ltime;
	t = time(0);

	if(t - i < 600L) {
		player->pleaseWait(600L-t+i);
		return(0);
	}
	chance = MIN(80, (int)(player->getSkillLevel("mistbane") * 20) + bonus((int) player->piety.getCur()));


	if(mrand(1, 100) > player->getLuck() + player->getSkillLevel("mistbane") * 2)
		chance = 10;

	if(mrand(1, 100) <= chance) {
		player->print("You imbue yourself with positive energy.\n");
		broadcast(player->getSock(), player->getParent(), "%M imbues %sself with positive energy.", player, player->himHer());
		player->checkImprove("mistbane", true);
		player->setFlag(P_MISTBANE);
		player->lasttime[LT_MISTBANE].ltime = t;
		player->lasttime[LT_MISTBANE].interval = 180L;

	} else {
		player->print("You failed to imbue yourself with positive energy.\n");
		broadcast(player->getSock(), player->getParent(), "%M tried to imbue %sself with positive energy.",
			player, player->himHer());
		player->checkImprove("mistbane", false);
		player->lasttime[LT_MISTBANE].ltime = t - 590L;
	}

	return(0);
}

//*********************************************************************
//						cmdSecond
//*********************************************************************
// This lets a ranger wield a weapon in their off-hand, getting 1/2
// damage, and 1/2 the thac0 bonus from it.

int cmdSecond(Player* player, cmd* cmnd) {
	Object	*object=0;

	player->clearFlag(P_AFK);

	if(!player->ableToDoCommand())
		return(0);

	if(!player->knowsSkill("dual")) {
		player->print("You are not skilled in the art of dual wielding.\n");
		return(0);
	}

	if(player->isEffected("frenzy")) {
		player->print("You cannot do that while attacking in a frenzy.\n");
		return(0);
	}

	if(cmnd->num < 2) {
		player->print("Wield what in your off hand?\n");
		return(0);
	}
	if(!player->ready[WIELD - 1]) {
		player->print("You must first be wielding a weapon in your primary hand.\n");
		return(0);
	}

	player->unhide();
	if(cmnd->num > 1) {

		object = player->findObject(player, cmnd, 1);
		if(!object) {
			player->print("You don't have that.\n");
			return(0);
		}

		if(object->getWearflag() != WIELD) {
			player->print("You can't wield that.\n");
			return(0);
		}

		if(!player->isCt() && (object->getActualWeight() >= player->ready[WIELD - 1]->getActualWeight())) {
			player->print("Your second weapon must be lighter then your primary weapon.\n");
			return(0);
		}
		if(object->getLevel() > player->getLevel() && !player->isCt()) {
			player->print("You are not experienced enough to use that.\n");
			return(0);
		}


		if(!player->canUse(object) || !player->canWield(object, SECONDOBJ))
			return(0);

		if(!player->willFit(object)) {
			player->printColor("%O isn't the right size for you.\n", object);
			return(0);
		}

		if(object->getMinStrength() > player->strength.getCur()) {
			player->printColor("You are currently not strong enough to wield %P.\n", object);
			return(0);
		}

		if(player->checkHeavyRestrict("dual wield"))
			return(false);

		player->equip(object, true);
		player->computeAttackPower();

		object->clearFlag(O_JUST_BOUGHT);
	}

	return(0);
}

//*********************************************************************
//						cmdBerserk
//*********************************************************************

int cmdBerserk(Player* player, cmd* cmnd) {
	long	i=0, t=0;
	int		chance=0;

	player->clearFlag(P_AFK);


	if(!player->ableToDoCommand())
		return(0);

	if(!player->knowsSkill("berserk")) {
		player->print("You don't know how to go berserk!\n");
		return(0);
	}

	if(	player->getClass() == CLERIC &&
		player->getDeity() == ARES &&
		(player->getAdjustedAlignment() < PINKISH || player->getAdjustedAlignment() > LIGHTBLUE)
	) {
		player->print("Your soul must be disciplined or you cannot go berserk.\n");
		return(0);
	}

	if(player->isEffected("berserk")) {
		player->print("You are already berserk.\n");
		return(0);
	}


	if(player->isEffected("strength")) {
		player->print("Your magically enhanced strength prevents you from going berserk.\n");
		return(0);
	}
	if(player->isEffected("enfeeblement")) {
		player->print("Your magically reduced strength prevents you from going berserk.\n");
		return(0);
	}
	if(player->isEffected("fortitude")) {
		player->print("Your magically enhanced health prevents you from going berserk.\n");
		return(0);
	}
	if(player->isEffected("weakness")) {
		player->print("Your magically reduced health prevents you from going berserk.\n");
		return(0);
	}


	if(player->flagIsSet(P_SITTING)) {
		player->print("You have to be standing to go berserk.\n");
		return(0);
	}

	i = player->lasttime[LT_BERSERK].ltime;
	t = time(0);

	if(t - i < 600L && !player->isCt()) {
		player->pleaseWait(600L-t+i);
		return(0);
	}

	chance = MIN(85, (int)(player->getSkillLevel("berserk") * 10) + (bonus((int) player->strength.getCur()) * 5));

	if(mrand(1, 100) <= chance) {
		player->print("You go berserk.\n");
		broadcast(player->getSock(), player->getParent(), "%M goes berserk!", player);
		player->checkImprove("berserk", true);
		// TODO: SKILLS: Add a modifier based on berserk skill level
		player->addEffect("berserk", 120L, 30);
		if(player->getClass() == CLERIC && player->getDeity() == ARES)
		    player->addEffect("berserk", 120L, 30);
		else
		    player->addEffect("berserk", 120L, 50);
		player->computeAC();
		player->computeAttackPower();
		player->lasttime[LT_BERSERK].ltime = t;
		player->lasttime[LT_BERSERK].interval = 600L;
		player->interruptDelayedActions();
	} else {
		player->print("You failed to gather your strength.\n");
		player->checkImprove("berserk", false);
		broadcast(player->getSock(), player->getParent(), "%M runs around trying to go berserk.", player);
		player->lasttime[LT_BERSERK].ltime = t - 590L;
	}
	return(0);
}


//*********************************************************************
//						cmdCircle
//*********************************************************************
// This function allows fighters and barbarians to run circles about an
// enemy, confusing it for several seconds.

int cmdCircle(Player* player, cmd* cmnd) {
	Creature* target=0;
	Monster	*mTarget=0;
	Player	*pTarget=0;
	int		chance=0, delay=0;
	double level = 0.0;

	if(!player->ableToDoCommand())
		return(0);

	if(!player->knowsSkill("circle")) {
		player->print("You lack the skills to circle anything effectively!\n");
		return(0);
	}

    if(!(target = player->findVictim(cmnd, 1, true, false, "Circle whom?\n", "You don't see that here.\n")))
		return(0);
    
	pTarget = target->getAsPlayer();

	mTarget = target->getAsMonster();

	if(!player->canAttack(target))
		return(0);

	if(!player->isCt()) {
		if(!player->checkAttackTimer(true))
			return(0);

		if(pTarget) {
			if(pTarget->isEffected("mist")) {
				player->print("You can't circle a mist?!\n");
				return(0);
			}

			if(player->vampireCharmed(pTarget) || (pTarget->hasCharm(player->getName()) && player->flagIsSet(P_CHARMED))) {
				player->print("You are too fond of %N to do that.\n", pTarget);
				return(0);
			}
		}
	}


	player->smashInvis();
	player->interruptDelayedActions();

	if(player->flagIsSet(P_LAG_PROTECTION_SET)) // Activates Lag protection.
		player->setFlag(P_LAG_PROTECTION_ACTIVE);


	level = player->getSkillLevel("circle");
	if(	player->getClass() == FIGHTER &&
		(player->getSecondClass() == THIEF || player->getSecondClass() == MAGE)
	)
		level = MAX(1, (int)level-2);
	if(player->getClass() == CLERIC && player->getSecondClass() == FIGHTER)
		level = MAX(1, (int)level-2);

	chance = 50 + (int)((level-target->getLevel())*20) +
		(bonus((int) player->dexterity.getCur()) -bonus((int) target->dexterity.getCur()))*2;

	// Having less then average dex has a major effect on circling chances.
	// This is being done because there is no save against circle, and there is one
	// against stun, thus making barbs and fighters extremely powerful comparatively
	// if this is not done. - TC
	if(player->dexterity.getCur()/10 < 9 && (target->dexterity.getCur()/10 > player->dexterity.getCur()/10))
		chance -= 10*(9 - (player->dexterity.getCur()/10));

	if(mTarget) {
		if(mTarget->isUndead() || mTarget->flagIsSet(M_RESIST_CIRCLE))
			chance -= (5 + target->getLevel()*2);
		chance = MIN(80, chance);

		mTarget->addEnemy(player);
	}



	if((mTarget && mTarget->flagIsSet(M_NO_CIRCLE)) || player->isBlind())
		chance = 1;
	//player->checkTarget(target);

	if(player->isCt()) chance = 101;

	if(mrand(1,100) <= chance && (mrand(1,100) > ((target->dexterity.getCur()/10)/2))) {
		if(mTarget) {
			if(!mTarget->flagIsSet(M_RESIST_CIRCLE) && !mTarget->isUndead())
				delay = MAX(6, (mrand(6,10) + (MIN(3,((bonus((int) player->dexterity.getCur()) -
						bonus((int) target->dexterity.getCur()))/2)))));
			else
				delay = mrand(6,9);
		} else
			delay = mrand(6,10);



		target->stun(delay);

		player->print("You circle %N.\n", target);
		player->checkImprove("circle", true);
		log_immort(false, player, "%s circled %s.\n", player->getCName(), target->getCName());

		if(mTarget && player->isPlayer()) {
			if(mTarget->flagIsSet(M_YELLED_FOR_HELP) && (mrand(1,100) <= (MAX(15, (mTarget->inUniqueRoom() ? mTarget->getUniqueRoomParent()->wander.getTraffic() : 15)/2)))) {
				mTarget->summonMobs(player);
				mTarget->clearFlag(M_YELLED_FOR_HELP);
				mTarget->setFlag(M_WILL_YELL_FOR_HELP);
			}

			if(mTarget->flagIsSet(M_WILL_YELL_FOR_HELP) && !mTarget->flagIsSet(M_YELLED_FOR_HELP)) {
				mTarget->checkForYell(player);
			}
		}

		target->print("%M circles you.\n", player);
		broadcast(player->getSock(), target->getSock(), player->getParent(), "%M circles %N.", player, target);
		player->updateAttackTimer(true, DEFAULT_WEAPON_DELAY - 10);

		if(mTarget) {
		    // A successful circle gives 5% of the target's max health as threat
		    mTarget->adjustThreat(player, tMAX<long>((long)(mTarget->hp.getMax()*0.05), 2));
		}


	} else {
		player->print("You failed to circle %N.\n", target);
		player->checkImprove("circle", false);
		target->print("%M tried to circle you.\n", player);
		broadcast(player->getSock(), target->getSock(), player->getParent(), "%M tried to circle %N.", player, target);
		player->updateAttackTimer(true, DEFAULT_WEAPON_DELAY);
		if(mTarget) {
            // An un-successful circle gives 2.5% of the target's max health as threat
            mTarget->adjustThreat(player, tMAX<long>((long)(mTarget->hp.getMax()*0.025),1) );
        }
	}

	return(0);
}

//*********************************************************************
//						cmdBash
//*********************************************************************
// This function allows fighters and berserkers to "bash" an opponent,
// doing less damage than a normal attack, but knocking the opponent
// over for a few seconds, leaving them unable to attack back.

int cmdBash(Player* player, cmd* cmnd) {
	Creature* creature=0;
	Player	*pCreature=0;
	long	t = time(0);
	int		chance=0;
	double level=0.0;

	if(!player->ableToDoCommand())
		return(0);


	if(!player->knowsSkill("bash")) {
		player->print("You lack the skills to effectively bash anything!\n");
		return(0);
	}
	if(!player->isCt()) {
		if(!player->ready[WIELD-1] && player->getSize() < SIZE_LARGE) {
			player->print("You are too small to bash without a weapon.\n");
			return(0);
		}
		if(player->ready[WIELD-1] && player->ready[WIELD-1]->getWeaponCategory() == "ranged") {
			player->print("You can't use a ranged weapon to bash someone!\n");
			return(0);
		}
	}
    if(!(creature = player->findVictim(cmnd, 1, true, false, "Bash whom?\n", "You don't see that here.\n")))
   		return(0);

    if(creature)
		pCreature = creature->getAsPlayer();

    if(!player->canAttack(creature))
		return(0);

	if(!player->isCt()) {
		if(!pCreature) {
			if(creature->getAsMonster()->isEnemy(player)) {
				player->print("Not while you're already fighting %s.\n", creature->himHer());
				return(0);
			}
		}
	}

	if(!player->checkAttackTimer(true))
		return(0);

	player->updateAttackTimer();
	player->lasttime[LT_KICK].ltime = t;
	player->lasttime[LT_KICK].interval = (player->ready[WIELD-1]->getWeaponDelay()/10);

	if(player->getClass() == CLERIC && player->getDeity() == ARES) {
		player->lasttime[LT_SPELL].ltime = t;
		player->lasttime[LT_SPELL].interval = 3L;
	}
	// All the logic to check if a weapon can hit the target is inside the attackCreature function
	// so only put anything specific to bash here, or check for ATTACK_BASH in attackCreature

	player->unhide();
	player->smashInvis();
	player->interruptDelayedActions();

	if(creature->isMonster()) {
		creature->getAsMonster()->addEnemy(player);
	}

	if(player->flagIsSet(P_LAG_PROTECTION_SET)) // Activates Lag protection.
		player->setFlag(P_LAG_PROTECTION_ACTIVE);

	level = player->getSkillLevel("bash");

	if(player->getClass() == CLERIC && player->getSecondClass() == FIGHTER)
		level = MAX(1, (int)level-2);
	else if(player->getClass() == CLERIC && player->getDeity() == ARES)
		level = MAX(1, (int)level-3);


	chance = 50 + (int)((level-creature->getLevel())*10) +
			bonus((int) player->strength.getCur())*3 +
			(bonus((int) player->dexterity.getCur()) -bonus((int) creature->dexterity.getCur()))*2;
	chance += player->getClass()==BERSERKER ? 10:0;

	chance = player->getClass()==BERSERKER ? MIN(90, chance) : MIN(85, chance);

	if(player->isBlind())
		chance = MIN(20, chance);

	if(creature->isMonster() && (player->ready[WIELD-1] &&
			player->ready[WIELD-1]->flagIsSet(O_ALWAYS_CRITICAL)) && creature->flagIsSet(M_NO_AUTO_CRIT))
		chance = 0; // automatic miss with autocrit weapon.

	if(player->isCt()) chance = 101;
	// For bash we have a bash chance, and then a normal attack miss chance
	if(mrand(1,100) <= chance) {
		// We made the bash check, do the attack
		player->attackCreature(creature, ATTACK_BASH);
	}
	else {
		player->print("Your bash failed.\n");
		player->checkImprove("bash", false);
		creature->print("%M tried to bash you.\n", player);
		broadcast(player->getSock(),  creature->getSock(), creature->getRoomParent(),
			"%M tried to bash %N.", player, creature);
	}

	return(0);

}

//*********************************************************************
//						cmdKick
//*********************************************************************
// This function allows fighters to kick their oopponents every 12
// seconds, in order to do a little extra damage. -- TC

int cmdKick(Player* player, cmd* cmnd) {
	Creature* creature=0;
	long	i=0, t=0;
	int		chance=0;


	if(!player->ableToDoCommand())
		return(0);

	if(!player->isStaff()) {
		if(!player->knowsSkill("kick")) {
			player->print("You lack the skills to kick effectively.\n");
			return(0);
		}
	}

    if(!(creature = player->findVictim(cmnd, 1, true, false, "Kick whom?\n", "You don't see that here.\n")))
   		return(0);


	if(!player->canAttack(creature))
		return(0);


	i = LT(player, LT_KICK);
	t = time(0);

	if(i > t && !player->isDm()) {
		player->pleaseWait(i-t);
		return(0);
	}

	// Kick
	player->lasttime[LT_KICK].ltime = t;
	if(player->getClass() == FIGHTER || player->getClass() == MONK)
		player->lasttime[LT_KICK].interval = 12L;
	else
		player->lasttime[LT_KICK].interval = 15L;


	if(player->getClass() != MONK) {
		player->lasttime[LT_DISARM].ltime = t;
		player->lasttime[LT_DISARM].interval = 6;
	}

	player->unhide();
	player->smashInvis();
	player->interruptDelayedActions();

	if(player->flagIsSet(P_LAG_PROTECTION_SET)) // Activates Lag protection.
		player->setFlag(P_LAG_PROTECTION_ACTIVE);

	if(creature->isMonster()) {
		creature->getAsMonster()->addEnemy(player);
	}

	chance = 40 + (int)((player->getSkillLevel("kick") - creature->getLevel())*10) +
			(3*bonus((int) player->dexterity.getCur()) - bonus((int) creature->dexterity.getCur()))*2;

	if(player->getClass() == ROGUE)
		chance -= (15 - (bonus((int) player->dexterity.getCur()) - bonus((int) creature->dexterity.getCur())));


	chance = MAX(0, MIN(95, chance));

	if(player->isBlind())
		chance = MIN(10, chance);

	if(creature->flagIsSet(M_NO_KICK))
		chance = 0;

	if(player->isDm())
		chance = 101;

	if(mrand(1,100) <= chance) {
		// Like bash, two checks, first is to see if the kick was sucessfull, 2nd check
		// is to see if we actually hit the target

		player->attackCreature(creature, ATTACK_KICK);
	}
	else {
		player->print("Your kick was ineffective.\n");
		player->checkImprove("kick", false);
		creature->print("%M tried to kick you.\n", player);
		broadcast(player->getSock(),  creature->getSock(), creature->getRoomParent(), "%M tried to kick %N.", player, creature);
	}

	return(0);
}


//*********************************************************************
//						scentTrack
//*********************************************************************
// determines if this player finds tracks by smell or by sight

bool scentTrack(const Player* player) {
	return(player->getClass() == WEREWOLF || player->getRace() == MINOTAUR);
}

//*********************************************************************
//						canTrack
//*********************************************************************

bool canTrack(const Player* player) {
	if(!player->ableToDoCommand())
		return(false);

	if(player->isBlind() && !scentTrack(player) && !player->isStaff()) {
		player->printColor("^CYou can't see any tracks! You're blind!\n");
		return(false);
	}

	if(!player->knowsSkill("track")) {
		player->print("You lack the proper training to find tracks.\n");
		return(false);
	}

	if(player->checkHeavyRestrict("find tracks"))
		return(false);

	if(player->flagIsSet(P_SITTING)) {
		player->print("You must stand up first!\n");
		return(false);
	}

	return(true);
}

//*********************************************************************
//						doTrack
//*********************************************************************

void doTrack(Player* player) {
	Track*	track=0;
	int		chance=0;
	int		skLevel = (int)player->getSkillLevel("track");

	player->clearFlag(P_AFK);
	player->unhide();

	if(!canTrack(player))
		return;

	if(player->inAreaRoom())
		track = player->getAreaRoomParent()->area->getTrack(&player->getAreaRoomParent()->mapmarker);
	else if(player->inUniqueRoom())
		track = &player->getUniqueRoomParent()->track;

	chance = 25 + (int)((bonus((int)player->dexterity.getCur()) + skLevel)*5);

	if(!track || mrand(1,100) > chance) {
		player->print("You fail to find any tracks.\n");
		player->checkImprove("track", false);
		return;
	}

	if(track->getDirection() == "") {
		player->print("There are no tracks in this room.\n");
		return;
	}

	if(scentTrack(player))
		player->printColor("You smell tracks leading to the %s^x.\n", track->getDirection().c_str());
	else
		player->printColor("You find tracks leading to the %s^x.\n", track->getDirection().c_str());

	if(skLevel >= 5 && track->getSize() != NO_SIZE)
		player->print("The tracks are %s.\n", getSizeName(track->getSize()).c_str());
	if(skLevel >= 10 && track->getNum())
		player->print("You find %d unique sets of tracks.\n", track->getNum());

	player->checkImprove("track", true);
}

void doTrack(const DelayedAction* action) {
	doTrack(action->target->getAsPlayer());
}

//*********************************************************************
//						cmdTrack
//*********************************************************************
// This function is the routine that allows players to search
// for tracks in a room. If successful, they will be told what
// direction the last person who was in the room went.

int cmdTrack(Player* player, cmd* cmnd) {
	long	i=0, t=0;

	player->clearFlag(P_AFK);
	
	if(!canTrack(player))
		return(0);
	if(gServer->hasAction(player, ActionTrack)) {
		player->print("You are already looking for tracks!\n");
		return(0);
	}

	t = time(0);
	i = LT(player, LT_TRACK);

	if(!player->isStaff() && t < i) {
		player->pleaseWait(i-t);
		return(0);
	}

	player->lasttime[LT_TRACK].ltime = t;
	player->lasttime[LT_TRACK].interval = 5 - bonus((int)player->dexterity.getCur());

	if(player->isStaff())
		player->lasttime[LT_TRACK].interval = 1;

	player->interruptDelayedActions();

	// big rooms take longer to search
	if(player->getRoomParent()->getSize() >= SIZE_HUGE) {
		// doSearch calls unhide, no need to do it twice
		player->unhide();

		gServer->addDelayedAction(doTrack, player, 0, ActionTrack, player->lasttime[LT_TRACK].interval);

		if(scentTrack(player)) {
			player->print("You begin sniffing for tracks.\n");
			broadcast(player->getSock(), player->getParent(), "%M sniffs for tracks.", player);
		} else {
			player->print("You begin searching for tracks.\n");
			broadcast(player->getSock(), player->getParent(), "%M searches for tracks.", player);
		}
	} else {
		if(scentTrack(player))
			broadcast(player->getSock(), player->getParent(), "%M sniffs for tracks.", player);
		else
			broadcast(player->getSock(), player->getParent(), "%M searches for tracks.", player);

		doTrack(player);
	}

	return(0);
}

//*********************************************************************
//						cmdHarmTouch
//*********************************************************************
// This will allow death knights to harm touch once reaching 16th level.

int cmdHarmTouch(Player* player, cmd* cmnd) {
	Creature* creature=0;
	int		num=0, chance=0;
	long	t=0, i=0;


	player->clearFlag(P_AFK);

	if(!player->knowsSkill("harm")) {
		player->print("You are unable to use harm touch.\n");
		return(0);
	}

	if(player->getAdjustedAlignment() != BLOODRED && !player->isCt()) {
		player->print("Your soul must be of the utmost darkness to do that.\n");
		return(0);
	}


	i = player->lasttime[LT_LAY_HANDS].ltime;
	t = time(0);


	if(t-i < 1800L && !player->isCt()) {
		player->pleaseWait(1800L-t+i);
		return(0);
	}

    if(!(creature = player->findVictim(cmnd, 1, true, false, "Harm-touch whom?\n", "You don't see that here.\n")))
   		return(0);

    if(!player->canAttack(creature))
		return(0);

	player->unhide();
	player->smashInvis();
	player->interruptDelayedActions();

	if(	(creature->isMonster() && creature->isEffected("resist-magic")) ||
		(creature->isPlayer() && creature->isEffected("resist-magic"))
	) {
		if(!player->isCt() && mrand(1,100) > 50) {
			player->print("Your harm touch failed!\n");
			return(0);
		}
	}



	creature->print("%M hits you with fists shrouded in darkness!\n", player);
	broadcast(player->getSock(),  creature->getSock(), creature->getRoomParent(), "%M hits %N with fists shrouded in darkness!", player, creature);


	chance = 65 + ((int)(player->getSkillLevel("harm") - creature->getLevel())*10) +
			(2*(bonus((int)player->piety.getCur()) - bonus((int)creature->piety.getCur())));

	if(player->isCt())
		chance = 100;

	//	if(((creature->getClass() == LICH && creature->getLevel() >= 7) ||
	//		(creature->isEffected("lycanthropy") && creature->getClass() >=10)) && !player->isCt())
	//		chance = 0;
	if(creature->isMonster())
		creature->getAsMonster()->addEnemy(player);

	if(mrand(1,100) <= chance) {

		num = (int)(player->getSkillLevel("harm")*4) + mrand(1,6);
		player->print("The darkness within you flows into %N.\n", creature);
		player->printColor("You did %s%d^x damage!\n", player->customColorize("*CC:DAMAGE*").c_str(), num);
		player->checkImprove("harm", true);
		creature->print("%M harm touches you!\n", player);

		player->statistics.attackDamage(num, "harm touch");

		if(creature->getClass() == LICH) {
			player->doHeal(creature, num);
			player->print("Your darkness heals %N!\n", creature);
			creature->print("You are healed by %N's evil touch.\n", player);
		} else {
			creature->printColor("You lose %s%d^x hit points!\n", creature->customColorize("*CC:DAMAGE*").c_str(), num);
			player->doDamage(creature, num, CHECK_DIE);
		}
	} else {
		player->print("Your harm touch failed!\n");
		player->checkImprove("harm", false);
		creature->print("%s's attack had no effect.\n", player->upHisHer());
		broadcast(player->getSock(),  creature->getSock(), creature->getRoomParent(), "%M's attack failed.", player);
	}


	player->updateAttackTimer(true, DEFAULT_WEAPON_DELAY);
	player->lasttime[LT_LAY_HANDS].ltime = t;
	player->lasttime[LT_SPELL].ltime = t;
	player->lasttime[LT_READ_SCROLL].ltime = t;
	if(LT(player, LT_RENOUNCE) <= t) {
		player->lasttime[LT_RENOUNCE].ltime = t;
		player->lasttime[LT_RENOUNCE].interval = 3L;
	}

	player->lasttime[LT_LAY_HANDS].interval = 1800L;

	return(0);
}



//*********************************************************************
//						cmdBloodsacrifice
//*********************************************************************
// This function allows Death Knights to drain over their max hp for
// 2 minutes out of every 10.

int cmdBloodsacrifice(Player* player, cmd* cmnd) {
	long	i=0, t=0;
	int		chance=0;

	player->clearFlag(P_AFK);

	if(!player->ableToDoCommand())
		return(0);

	if(!player->knowsSkill("bloodsac")) {
		player->print("You cannot sacrifice your blood.\n");
		return(0);
	}

	if(player->isEffected("bloodsac")) {
		player->print("You're haven't finished your last sacrifice!\n");
		return(0);
	}

	i = player->lasttime[LT_BLOOD_SACRIFICE].ltime;
	t = time(0);

	if(t - i < 600L && !player->isStaff()) {
		player->pleaseWait(600L-t+i);
		return(0);
	}

	int level = (int)player->getSkillLevel("bloodsac");
	chance = MIN(85, (int)(level * 20) + bonus((int) player->piety.getCur()));
	player->interruptDelayedActions();
	player->hp.decrease(10);

	if(player->hp.getCur() < 1) {
		player->hp.setCur(1);
		player->print("You run out of blood before your ritual completes.\n");
		chance = 0;
	}

	if(mrand(1, 100) <= chance) {
		player->print("Your blood sacrifice infuses your body with increased vitality.\n");
		player->checkImprove("bloodsac", true);
		player->addEffect("bloodsac", 120L + 60L * (int)(level / 5));
		player->lasttime[LT_BLOOD_SACRIFICE].ltime = t;
		player->lasttime[LT_BLOOD_SACRIFICE].interval = 600L;
	} else {
		player->print("Your sacrifice fails.\n");
		player->checkImprove("bloodsac", false);
		player->lasttime[LT_BLOOD_SACRIFICE].ltime = t - 590L;
	}

	broadcast(player->getSock(), player->getParent(), "%M sacrifices %s blood.",
		player, player->hisHer());
	return(0);
}