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/
/*
 * combatSystem.cpp
 *	 Functions for the new combat mechanics
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * This software is distributed in accordance with 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 <sstream>
#include "commands.h"
#include "specials.h"
#include "effects.h"


//**********************************************************************
//						computeAttackPower
//**********************************************************************

int Player::computeAttackPower() {
	attackPower = 0;

	switch(cClass) {
		case FIGHTER:
		case DUNGEONMASTER:
			if(cClass2 == MAGE)
				attackPower = (strength.getCur() * 2) + (level);
			else if(cClass2 == THIEF)
				attackPower = (strength.getCur() * 2) + (level * 4);
			else
				attackPower = (strength.getCur() * 2) + (level * 8);
			break;
		case BERSERKER:
			attackPower = (strength.getCur() * 2) + (level * 8);
			break;
		case PALADIN:
		case DEATHKNIGHT:
			// TODO: This might need some tweaking with pray
			attackPower = strength.getCur() + piety.getCur() + (level * 4);
			break;
		case BARD:
		case WEREWOLF:
		case PUREBLOOD:
			attackPower = (strength.getCur() * 2) + (level * 4);
			break;
		case RANGER:
		case THIEF:
		case ASSASSIN:
		case ROGUE:
		case MONK:
			attackPower = strength.getCur() + dexterity.getCur() + (level * 4);
			break;
		case DRUID:
		    attackPower = strength.getCur() + (level * 2);
		    break;
		case CLERIC:
			attackPower = strength.getCur();

			if(cClass2 == ASSASSIN)
				attackPower += dexterity.getCur();

			switch(deity) {
				case CERIS:
					attackPower += (level);
					break;
				case ARES:
					attackPower += (level * 8);
					break;
				case ENOCH:
				case GRADIUS:
				case ARAMON:
				case ARACHNUS:
				default:
					attackPower += (level * 2);
					break;
			}
			break;
		case LICH:
		case MAGE:
			attackPower = strength.getCur();
			if(cClass2 == THIEF || cClass2 == ASSASSIN)
				attackPower += dexterity.getCur() + (level*2);
			break;
		default:
			attackPower = strength.getCur();
			break;
	}

	// Check equipment here for higher attack power



	return(attackPower);
}

//****************************************************************************
//						getBaseDamage
//****************************************************************************

unsigned int Creature::getBaseDamage() const {
	return(getAttackPower()/15);
}

//****************************************************************************
//						getDamageReduction
//****************************************************************************
// Returns the damage reduction factor when attacking the given target

float Creature::getDamageReduction(const Creature* target) const {
	float reduction = 0.0;
	float targetArmor = target->getArmor();
	float myLevel = level == 1 && isPlayer() ? 2 : level;
	reduction = ((targetArmor)/((targetArmor) + 43.24 + 18.38*myLevel));
	reduction = MIN(.75, reduction); // Max of 75% reduction
	return(reduction);
}

//**********************************************************************
//						getWeaponType
//**********************************************************************

const bstring Object::getWeaponType() const {
	if(!this || type != WEAPON)
		return("none");
	else
		return(subType);
}

//**********************************************************************
//						getArmorType
//**********************************************************************

const bstring Object::getArmorType() const {
	if(!this || type != ARMOR)
		return("none");
	else
		return(subType);
}

//**********************************************************************
//						getWeaponCategory
//**********************************************************************

const bstring Object::getWeaponCategory() const {
	if(!this)
		return("none");

	SkillInfo* weaponSkill = gConfig->getSkill(subType);

	if(type != WEAPON || !weaponSkill)
		return("none");

	bstring category = weaponSkill->getGroup();
	// Erase the 'weapons-' to leave the category
	category.erase(0, 8);

	return(category);
}

//**********************************************************************
//						getWeaponVerb
//**********************************************************************

const bstring  Object::getWeaponVerb() const {
	const bstring category = getWeaponCategory();

	if(category == "crushing")
		return("crush");
	else if(category == "piercing")
		return("stab");
	else if(category == "slashing")
		return("slash");
	else if(category == "ranged")
		return("shoot");
	else if(category == "chopping")
		return("chop");
	else
		return("thwack");
}

//**********************************************************************
//						getWeaponVerbPlural
//**********************************************************************

const bstring  Object::getWeaponVerbPlural() const {
	const bstring category = getWeaponCategory();

	if(category == "crushing")
		return("crushes");
	else if(category == "piercing")
		return("stabs");
	else if(category == "slashing")
		return("slashes");
	else if(category == "ranged")
		return("shoots");
	else if(category == "chopping")
		return("chops");
	else
		return("thwacks");
}

//**********************************************************************
//						getWeaponVerbPast
//**********************************************************************

const bstring Object::getWeaponVerbPast() const {
	const bstring category = getWeaponCategory();

	if(category == "crushing") {
		if(mrand(0,1))
			return("crushed");
		else
			return("bludgeoned");
	}
	else if(category == "piercing") {
		if(mrand(0,1))
			return("impaled");
		else
			return("stabbed");
	}
	else if(category == "slashing") {
		if(mrand(0,1))
			return("gutted");
		else
			return("slashed");
	}
	else if(category == "ranged")
		return("shot");
	else if(category == "chopping") {
		if(mrand(0,1))
			return("chopped");
		else
			return("cleaved");
	}
	else
		return("hit");
}

//**********************************************************************
//						needsTwoHands
//**********************************************************************

bool Object::needsTwoHands() const {
	const bstring weaponType = getWeaponType();

	if(flagIsSet(O_TWO_HANDED))
		return(true);
	if(	weaponType == "great-axe" || weaponType == "great-mace" ||
		weaponType == "great-hammer" || weaponType == "staff" ||
		weaponType == "great-sword" || weaponType == "polearm"
	)
		return(true);
	if((weaponType == "bow" || weaponType == "crossbow") && !flagIsSet(O_SMALL_BOW))
		return(true);

	return(false);
}

//**********************************************************************
//						setWeaponType
//**********************************************************************

bool Object::setWeaponType(const bstring& newType) {
	SkillInfo* weaponSkill = gConfig->getSkill(newType);
	bstring category = "";
	if(weaponSkill) {
		category = weaponSkill->getGroup();
		category = category.left(6);
	}

	if(!weaponSkill || category != "weapon") {
		printf("Invalid weapon type: %s!\n", newType.c_str());
		return(false);
	}
	subType = newType;
	return(true);
}

//**********************************************************************
//						setArmorType
//**********************************************************************

bool Object::setArmorType(const bstring& newType) {
	// Armor type must be ring, shield, or one of the armor type skills
	if(newType != "ring" && newType != "shield") {
		SkillInfo* weaponSkill = gConfig->getSkill(newType);
		bstring category = "";
		if(weaponSkill) {
			category = weaponSkill->getGroup();
			category = category.left(5);
		}

		if(!weaponSkill || category != "armor") {
			printf("Invalid armor type: %s!\n", newType.c_str());
			return(false);
		}
	}
	subType = newType;
	return(true);
}

//**********************************************************************
//						setSubType
//**********************************************************************

bool Object::setSubType(const bstring& newType) {
	// These must be set with the appropriate function
	if(type == ARMOR || type == WEAPON)
		return(false);

	subType = newType;
	return(true);
}

//**********************************************************************
//						getWeaponSkill
//**********************************************************************

int Monster::getWeaponSkill(const Object* weapon) const {
	// Same skills for all weapons
	return(weaponSkill);
}

//**********************************************************************
//						getWeaponSkill
//**********************************************************************

int Player::getWeaponSkill(const Object* weapon) const {;
	int bonus = 0;

	// Bless improves your chance to hit
	if(isEffected("bless"))
		bonus += 10;

//	print("Looking at weapon skill for %s.\n", weapon ? weapon->getCName() : "null object");
	bstring weaponType;
	if(weapon)
		weaponType = weapon->getWeaponType();
	else
		weaponType = getUnarmedWeaponSkill();

	// we're very confused about what type of weapon this is
	if(weaponType == "")
		weaponType = "bare-hand";

	Skill* weaponSkill = getSkill(weaponType);
	if(!weaponSkill)
		return(0);
	else
		return(weaponSkill->getGained() + bonus);
}

//**********************************************************************
//						getDefenseSkill
//**********************************************************************

int Monster::getDefenseSkill() const {
	return(defenseSkill);
}

//**********************************************************************
//						getDefenseSkill
//**********************************************************************

int Player::getDefenseSkill() const {
	int bonus = 0;
	// Protection makes you harder to hit
	if(isEffected("protection"))
		bonus += 10;
	Skill* defenseSkill = getSkill("defense");
	if(!defenseSkill)
		return(-1);
	else
		return(defenseSkill->getGained() + bonus);
}

//**********************************************************************
//						AttackResult
//**********************************************************************
// defense - skill
// 295 - 300 = -5 * .01% less chance to miss
// 320 - 300 = 20 * .01% more chance to miss

AttackResult Creature::getAttackResult(Creature* victim, const Object* weapon, int resultFlags, int altSkillLevel) {
	/*
	int pFd;
	if(isPlayer())
		pFd = fd;
	else
		pFd = victim->getSock();
	*/
	int mySkill=0;

	if(altSkillLevel != -1) {
		// For when we want to look at an alternative skill, like kick
		mySkill = altSkillLevel;
	} else {
		mySkill = getWeaponSkill(weapon);
	}
	int defense = victim->getDefenseSkill();
	int difference = defense - mySkill;


	double missChance=0;
	double dodgeChance=0;
	double parryChance=0;
	double glancingChance=0;
	double blockChance=0;
	double criticalChance=0;
	double fumbleChance=0;
	//double hitChance=0;

	EffectInfo* effect=0;

	missChance = victim->getMissChance(difference);

	if(victim->isEffected("blur") && !isEffected("true-sight"))
		missChance += victim->getEffect("blur")->getStrength();

	if(victim->getRoomParent()->isEffected("dense-fog")) {
		effect = victim->getRoomParent()->getEffect("dense-fog");
		if(!effect->isOwner(this))
			missChance += effect->getStrength();
	}

	if(resultFlags & DOUBLE_MISS)
		missChance *= 2;

	int missCutoff = (int)(missChance * 100);

	if(resultFlags & NO_DODGE)
		dodgeChance = 0;
	else
		dodgeChance = victim->getDodgeChance(this, difference);
	int dodgeCutoff = (int)(missCutoff + (dodgeChance * 100));

	if(resultFlags & NO_PARRY)
		parryChance = 0;
	else
		parryChance = victim->getParryChance(this, difference);
	int parryCutoff = (int)(dodgeCutoff + (parryChance * 100));

	if(resultFlags & NO_GLANCING)
		glancingChance = 0;
	else
		glancingChance = victim->getGlancingBlowChance(this, difference);
	int glancingCutoff = (int)(parryCutoff + (glancingChance * 100));

	if(resultFlags & NO_BLOCK)
		blockChance = 0;
	else
		blockChance = victim->getBlockChance(this, difference);
	int blockCutoff = (int)(glancingCutoff + (blockChance * 100));

	if((resultFlags & NO_CRITICAL) || victim->immuneCriticals())
		criticalChance = 0;
	else
		criticalChance = getCriticalChance(difference);
	int criticalCutoff = (int)(blockCutoff + (criticalChance * 100));

	if(resultFlags & NO_FUMBLE)
		fumbleChance = 0;
	else
		fumbleChance = getFumbleChance(weapon);
	int fumbleCutoff = (int)(criticalCutoff + (fumbleChance * 100));

	//hitChance = MAX(0, 100.0 - missChance - dodgeChance - parryChance - glancingChance - blockChance - criticalChance - fumbleChance);
	//int hitCutoff = (int)(fumbleCutoff + (hitChance * 100));

	// Auto miss with an always crit weapon vs a no crit monster
	if(weapon && weapon->flagIsSet(O_ALWAYS_CRITICAL)) {
		if(victim->mFlagIsSet(M_NO_AUTO_CRIT) || victim->immuneCriticals())
			missCutoff = 10000;
		else {
			missCutoff = dodgeCutoff = parryCutoff = glancingCutoff = blockCutoff = -1;
			criticalCutoff = 10000;
		}

	}

//	printColor("^y%d attack skill %d defense skill, %d difference.\n", mySkill, defense, difference);
//	printColor("^cChances: ^C%f^c miss, ^C%f^c dodge, ^C%f^c parry, ^C%f^c glancing, ^C%f^c block, ^C%f^c critical, ^C%f^c fumble, ^C%f^c leftover\n",
//			missChance, dodgeChance, parryChance, glancingChance, blockChance, criticalChance, fumbleChance, hitChance);
//	printColor("^gCutoffs: ^G%d^g miss,  ^G%d^g dodge,  ^G%d^g parry,  ^G%d^g glancing,  ^G%d^g block, ^G%d^g critical ^G%d^g fumble ^G%d^g hit.\n",
//			missCutoff, dodgeCutoff, parryCutoff, glancingCutoff, blockCutoff, criticalCutoff, fumbleCutoff, hitCutoff);
//
	int randNum = mrand(0, 10000);
	AttackResult result;

	if(randNum < missCutoff)
		result = (ATTACK_MISS);
	else if(randNum < dodgeCutoff)
		result = (ATTACK_DODGE);
	else if(randNum < parryCutoff)
		result = (ATTACK_PARRY);
	else if(randNum < glancingCutoff)
		result = (ATTACK_GLANCING);
	else if(randNum < blockCutoff)
		result = (ATTACK_BLOCK);
	else if(randNum < criticalCutoff)
		result = (ATTACK_CRITICAL);
	else if(randNum < fumbleCutoff)
		result = (ATTACK_FUMBLE);
	else
		result = (ATTACK_HIT);

	if(result == ATTACK_HIT || result == ATTACK_CRITICAL)
		if(victim->kamiraLuck(this))
			result = ATTACK_MISS;

	return(result);
}

//**********************************************************************
//						adjustChance
//**********************************************************************

int Creature::adjustChance(const int &difference) {
	double adjustment = 0;
	// defense - skill
	// 295 - 300 = -5 * .01% less chance to miss == negative difference, defense LOWER than weapon
	// 320 - 300 = 20 * .01% more chance to miss == positive difference, defense HIGHER than weapon

	// Now adjust it based on weapon skill & defense
	if(difference > 0) {
		// Defense is HIGHER than weapon skill
		if(isMonster()) {
			// Mobs get more out of higher defence than players
			if(difference > 10)
				adjustment = 0.4;
			else
				adjustment = 0.1;
		} else {
			adjustment = 0.1;
		}
	} else {
		// Rating < 0
		// Weapon skill is HIGHER than defense skill
		if(isPlayer())
			adjustment = 0.04;
		else
			adjustment = 0.04;
	}
	return((int)(difference * adjustment));
	//chance += (difference * adjustment);
}

//**********************************************************************
//						getFumbleChance
//**********************************************************************

double Creature::getFumbleChance(const Object* weapon) {
	double chance = 2.0;

	if(!weapon || weapon->flagIsSet(O_CURSED) || isDm()) {
		chance = 0.0;
	}
	else {
		double weaponSkill = getSkillLevel(weapon->getWeaponType());
		// Spread the reduction over all 300 skill points, leaving a .01 chance to fumble
		// even at 300 skill
		chance -= (weaponSkill / 151.0);

		chance = MAX(0.0, chance);
	}
	return(chance);
}

//**********************************************************************
//						getCriticalChance
//**********************************************************************

double Creature::getCriticalChance(const int& difference) {
	double chance = 5.0;

	chance -= adjustChance(difference);
	chance = MAX(0.0, chance);
	return(chance);
}

//**********************************************************************
//						getBlockChance
//**********************************************************************

double Creature::getBlockChance(Creature* attacker, const int& difference) {
	if(isPlayer()) {
		if(!knowsSkill("block"))
			return(0);

		// Players need a shield to block
		if(!ready[SHIELD-1])
			return(0);
	}
	double chance = 5.0;
	chance += adjustChance(difference);
	// Max chance of 5.0% if a monster
	if(isMonster())
		chance = MIN(5.0, chance);

	chance = MAX(0.0, chance);
	return(chance);
}

//**********************************************************************
//						getGlancingBlowChance
//**********************************************************************
// A glancing blow is the opposite of a critical hit; reduced damage
// when a player or pet is attacking a monster but only against
// monsters of the same level or higher

double Creature::getGlancingBlowChance(Creature* attacker, const int& difference) {
	if(isPlayer() || isPet() || (attacker->isMonster() && !attacker->isPet()))
		return(0);

	if(level < attacker->getLevel())
		return(0);

	double chance = 10.0 + (difference * 0.5);
	chance = MAX(0.0, chance);
	return(chance);
}

//**********************************************************************
//						getParryChance
//**********************************************************************
// Chance that they will parry or riposte an attack.
// 50% of parry will be a riposte

double Creature::getParryChance(Creature* attacker, const int& difference) {
	if(isPlayer()) {
		if(!canDodge(attacker) || !canParry(attacker))
			return(0);

		if(!knowsSkill("parry"))
			return(0);

	} else {
//		if(level < 7)
//			return(false);
	}
	double chance = (dexterity.getCur() - 80) * .03;
	chance += adjustChance(difference);

	// Riposte is harder against some attacker types
	if(	attacker->type == DRAGON || attacker->type == DEMON || attacker->type == DEVIL ||
		attacker->type == GIANTKIN || attacker->type == DEVA || attacker->type == DINOSAUR ||
		attacker->type == ELEMENTAL
	)
		chance /= 2;

	int numEnm = 0;
	for(Monster* mons : getRoomParent()->monsters) {
	    if(mons->isPet())
	        continue;
	    if(mons->isEnemy(this))
	        if(numEnm++ > 1)
	            chance -= .02;
	}
	chance = MAX(0.0, chance);
	return(chance);
}

//**********************************************************************
//						canParry
//**********************************************************************

bool Creature::canParry(Creature* attacker) {
	if(attacker->isDm())
		return(false);
	if(isMonster())
		return(true);

	if(!ready[WIELD - 1])
		return(false);			// must have a weapon wielded in order to riposte.

	bstring weaponCategory = ready[WIELD - 1]->getWeaponCategory();
	bstring weaponType = ready[WIELD - 1]->getWeaponType();
	if((weaponCategory != "piercing" && weaponCategory != "slashing") || weaponType == "polearm")
		return(false);			// must use a piercing or slashing weapon to riposte

	if(ready[WIELD-1]->needsTwoHands())
		return(false);			// Cannot riposte with a two-handed weapon.

	int	combatPercent=0;
//	 If a this is overwhelmed by mass amounts of enemies, it is difficult if
//	 not impossible to find an opening to move enough to do a parry. The following
//	 code will calculate the chance of failure into a "combat percent". If a check
//	 against this percent fails, the this did not find enough of an opening to
//	 try a parry, so parry returns 0 without going off. -TC

	// +3% fail for every monster mad at this besides the one he's currently hitting
	combatPercent = 3*(tMAX(0,numEnemyMonInRoom(this)-1));
	// Group members are assumed to fight together to help one another.
	// -2% fail for every member in the this's group besides themself in the same room
	if(getGroup())
		combatPercent -= 2*(tMAX(0,getGroup()->getNumInSameRoom(this)));

	combatPercent = MAX(0,combatPercent);

	if(mrand(1,100) <= combatPercent)
		return(0); // Did not find a parry opening due to excessive combat. No parry.

	// Parry is not possible against some types of creatures
	if(	attacker->type == INSECT || attacker->type == AVIAN ||
		attacker->type == FISH || attacker->type == REPTILE || attacker->type == PLANT ||
		attacker->type == ETHEREAL || attacker->type == ASTRAL ||
		attacker->type == GASEOUS || attacker->type == ENERGY ||
		attacker->type == PUDDING || attacker->type == SLIME
	)
		return(false);

	long t = time(0);
	long i = LT(this, LT_RIPOSTE);

	if(t < i) {
		return(false);
	}
	if(ready[WIELD-1]->getShotsCur() < 1) // weapon must not be broken
		return(false);

	return(true);
}

//**********************************************************************
//						canDodge
//**********************************************************************

bool Creature::canDodge(Creature* attacker) {
	if(attacker->isDm())
		return(false);
	if(attacker->isMonster()) {
		if(attacker->flagIsSet(M_UN_DODGEABLE))
			return(false);
		if(attacker->flagIsSet(M_UNKILLABLE) && !isCt())
			return(false);
	}
	if(isPlayer()) {
		if(flagIsSet(P_UNCONSCIOUS)) // Can't dodge while unconscious
			return(false);

		if(getRoomParent()->isUnderwater() && !flagIsSet(P_FREE_ACTION))
			return(false);

		if(getRoomParent()->flagIsSet(R_NO_DODGE))
			return(false);

		// Players cannot dodge if stunned in any way.
		// Circle, bash, maul, bite, and stun will all
		// prevent dodge from functioning.
		if(flagIsSet(P_STUNNED))
			return(false);

		// Can't dodge what you cannot see
		if(!canSee(attacker))
			return(false);

		// Players waiting and hiding will not dodge, now so they won't auto unhide themselves.
		if(flagIsSet(P_HIDDEN))
			return(false);

	}
	return(true);
}

//**********************************************************************
//						getDodgeChance
//**********************************************************************
// What chance do we have to dodge the attacker?

double Creature::getDodgeChance(Creature* attacker, const int& difference) {
	if(!canDodge(attacker))
		return(false);

//	if(!knowsSkill("dodge"))
//		return(0);
//
	double chance = 0.0;
	Player* pPlayer = getAsPlayer();

	// Find the base chance
	if(pPlayer) {
		switch(cClass) {
			case RANGER:
				chance += (dexterity.getCur() * .06);
				break;
			case THIEF:
				chance += (dexterity.getCur() * .075);
				break;
			case ASSASSIN:
				chance += (dexterity.getCur() * .06);
				break;
			case ROGUE:
				chance += (dexterity.getCur() * .08);
				break;
			case FIGHTER:
			case BERSERKER:
				if(pPlayer->getSecondClass() == THIEF || pPlayer->getSecondClass() == ASSASSIN)
					chance += (dexterity.getCur() * .07);
				else
					chance += (1.0 + (dexterity.getCur() * .045));
				break;
			case BARD:
			case PALADIN:
			case DEATHKNIGHT:
			case WEREWOLF:
			case PUREBLOOD:
			case MONK:
				chance += (2.0 + (dexterity.getCur() * .05));
				break;
			case CLERIC:
				if(pPlayer->getSecondClass() == ASSASSIN) {
					chance += (dexterity.getCur() * .06);
					break;
				}
				switch(deity) {
					case KAMIRA:
					case ARACHNUS:
						chance += (piety.getCur() * .05);
						break;
					case CERIS:
					case ARES:
					case ENOCH:
					case GRADIUS:
					default:
						chance += (2.0 + dexterity.getCur() * .05);
						break;
				}
				break;
			case LICH:
			case MAGE:
				if(pPlayer->getSecondClass() == THIEF || pPlayer->getSecondClass() == ASSASSIN)
					chance += (dexterity.getCur() * .07);
				else
					chance += (1.0 + dexterity.getCur() * .06);
				break;
			default:
				break;
		}
	} else {
		// Not a player
		chance = 5.0;
	}

	// TODO: Adjust dodge based on armor weight


	chance += adjustChance(difference);
	chance = MAX(0.0, chance);
	return(chance);
}

//**********************************************************************
//						getMissChance
//**********************************************************************
//  What chance do we have to be missed?

double Creature::getMissChance(const int& difference) {
	// Base chance of 5% to miss
	double chance;

	if(difference > 10)
		chance = 7.0;
	else
		chance = 5.0;

	chance += adjustChance(difference);
	Player* pPlayer = getAsPlayer();
	// Class modification for miss
	if(pPlayer) {
		switch(cClass) {
			case RANGER:
			case THIEF:
			case ASSASSIN:
			case ROGUE:
				chance *= 1.0;
				break;
			case FIGHTER:
			case BERSERKER:
				chance *= 0.7;
				break;
			case MONK:
			case PALADIN:
			case DEATHKNIGHT:
			case WEREWOLF:
				chance *= 0.8;
				break;
			case PUREBLOOD:
			case BARD:
				chance *= 0.9;
				break;
			case CLERIC:
				switch(deity) {
					case ARES:
						chance *= 0.8;
						break;
					case ARACHNUS:
					case KAMIRA:
					case CERIS:
					case ENOCH:
					case GRADIUS:
						chance *= 1.0;
					default:
						chance *= 1.0;
						break;
				}
				break;
			case LICH:
			case MAGE:
				if(pPlayer->getSecondClass() == THIEF || pPlayer->getSecondClass() == ASSASSIN)
					chance *= 0.8;
				else
					chance *= 1.0;
				break;

		}
	} else {
		// Not a player
		chance *= 1.0;
	}

	chance = MAX(0.0, chance);
	return(chance);
}

//**********************************************************************
//						setWeaponSkill
//**********************************************************************

void Monster::setWeaponSkill(int amt) {
	weaponSkill = amt;
}

//**********************************************************************
//						setDefenseSkill
//**********************************************************************

void Monster::setDefenseSkill(int amt) {
	defenseSkill = amt;
}

//**********************************************************************
//						canHit
//**********************************************************************

bool Creature::canHit(Creature* victim, Object* weapon, bool glow, bool showFail) {
	//Monster* mVictim = victim->getMonster();
	Player* pVictim = victim->getAsPlayer();

	if(isMonster()) {

	} else {
		// Player attacking something
		bool silver = false;
		bool focused = false;
		int enchant = 0;

		if(cClass == MONK && !weapon && flagIsSet(P_FOCUSED))
			focused = true;

		if(cClass == MONK && !weapon && !ready[HELD-1] && ready[HANDS-1]) {
			enchant = abs(ready[HANDS-1]->getAdjustment());
			weapon = ready[HANDS-1];
		} else if(weapon) {
			enchant = abs(weapon->getAdjustment());
			if(weapon->flagIsSet(O_SILVER_OBJECT))
				silver = true;
		}

		if(pVictim) {
		// It's a player

			// DMs can hit vampires
			if(!isDm()) {
				if(pVictim->isEffected("mist")) {
					if(weapon) {
						if(	!weapon->flagIsSet(O_CAN_HIT_MIST) && !flagIsSet(P_MISTBANE) )
						{
							if(showFail) printColor("Your cannot hit a misted creature with your %1P.\n", weapon);
							return(false);
						}
					} else if(!flagIsSet(P_MISTBANE)) {
						if(showFail) print("You cannot physically hit a misted creature.\n");
						return(false);
					}
				}
			}

			if(!isDm() &&
				(// pVictim is a werewolf and higher than 10 and no silver
				(pVictim->isEffected("lycanthropy") && pVictim->getLevel() >=10 && !silver) ||
				// or pVictim is a lich and higher than 7
				(pVictim->getClass() == LICH && pVictim->getLevel() >=7 ) ||
				// or they have enchant only flag set
				pVictim->flagIsSet(P_ENCHANT_ONLY)
			)
				&& // and the attacker is
				// Not a werewolf
				!isEffected("lycanthropy") &&
				// and no weapon and not focused
				(  (!weapon && !focused) ||
					// or weapon and has no adjustment
					(weapon && enchant < 1)
				)
			) {
				if(showFail) {
					if(weapon) {
						if(weapon->getType() == WEAPON)
							print("Your %s has no effect on %N.\n", weapon->getCName(), pVictim);
						else
							print("Your %s have no effect on %N.\n", weapon->getCName(), pVictim);
					}
					else
						print("Your attack has no effect on %N.\n", pVictim);

					pVictim->print("%M's attack on you was uneffective.\n", this);
				}
				return(false);
			}
		} else {
			// Player vs Monster
			// Check if we can hit the monster
			if(	victim->flagIsSet(M_ENCHANTED_WEAPONS_ONLY) ||
				victim->flagIsSet(M_PLUS_TWO) ||
				victim->flagIsSet(M_PLUS_THREE)
			) {
				// At night level 19+ wolves can hit
				if(	isEffected("lycanthropy") &&
					!isDay() &&
					level > 19 &&
					victim->flagIsSet(M_ENCHANTED_WEAPONS_ONLY)
				) {
					if(glow) printColor("^WYour claws glow radiantly in the night against %N.\n", victim);
				}
				else if(cClass == MONK &&
					flagIsSet(P_FOCUSED) &&
					( (level >= 16 && victim->flagIsSet(M_ENCHANTED_WEAPONS_ONLY)) ||
							(level >= 16 && victim->flagIsSet(M_PLUS_TWO))
					)
				) {
					if(glow) printColor("^WYour fists glow with power against %N.\n", victim);
				}
				else if(weapon && (
						(victim->flagIsSet(M_ENCHANTED_WEAPONS_ONLY) && enchant > 0) ||
						(victim->flagIsSet(M_PLUS_TWO) && enchant > 1) ||
						(victim->flagIsSet(M_PLUS_THREE) && enchant > 2)
					)
				) {
					if(glow && weapon) {
						if(weapon->getType() == WEAPON)
							printColor("^WYour %s^W glows with power against %N.\n", weapon->getCName(), victim);
						else
							printColor("^WYour^W %s glow with power against %N.\n", weapon->getCName(), victim);
					}
				} else if(isDm()) {
					if(glow)
						printColor("^WYou ignore the laws of the land and attack %N anyway.\n", victim);
				} else {
					if(showFail) {
						if(weapon) {
							if(weapon->getType() == WEAPON)
								printColor("^cYour %s has no effect on %N.\n", weapon->getCName(), victim);
							else
								printColor("^cYour %s have no effect on %N.\n", weapon->getCName(), victim);
						} else
							printColor("^cYour attack has no effect on %N.\n", victim);
					}
					return(false);
				}
			}
		}

	}
	return(true);
}

//********************************************************************************
//						computeDamage
//********************************************************************************
// Returns 0 on normal computation, 1 if the weapon was shattered

int Player::computeDamage(Creature* victim, Object* weapon, AttackType attackType, AttackResult& result, Damage& attackDamage, bool computeBonus, int& drain, float multiplier) {
	int retVal = 0;
	Damage bonusDamage;
	bstring weaponCategory = weapon->getWeaponCategory();
	drain = 0;

	if(attackType == ATTACK_KICK) {
		if(computeBonus)
			bonusDamage.set(getBaseDamage()/2);
		attackDamage.set(mrand(2,6) + ::bonus(strength.getCur()));
		if((cClass == FIGHTER || cClass == MONK) && !cClass2) {
			attackDamage.add((int)(getSkillLevel("kick") / 4));
		}
	} else if(attackType == ATTACK_MAUL) {
		if(computeBonus)
			bonusDamage.set(getBaseDamage()/2);
		attackDamage.set(( mrand( (int)(level/2), (int)(level + 1)) + (strength.getCur()/10)));
		attackDamage.add(mrand(2, 4));
	} else {
		// Any non kick attack for now
		if(computeBonus)
			bonusDamage.set(getBaseDamage());

		 if(!weapon) {
			if(cClass == MONK) {
				attackDamage.set(mrand(1,2) + level/3 + mrand((1+level/4),(1+level)/2));
				if(strength.getCur() < 90) {
					attackDamage.set(attackDamage.get() - (90-strength.getCur())/10);
					attackDamage.set(MAX(1,attackDamage.get()));
				}
			} else {
				attackDamage.set(damage.roll());
				bonusDamage.set(bonusDamage.get() * 3 / 4);
			}
		}
		// TODO: Add in modifier based on weapon skill
	}

	if(weapon)
		attackDamage.add(weapon->damage.roll() + weapon->getAdjustment());

	if(isEffected("lycanthropy"))
		attackDamage.add(packBonus());

	attackDamage.set(MAX(1, attackDamage.get()));

	// Damage reduction on every hit
	if(cClass == PALADIN) {
		if(deity == GRADIUS) {
			if(getAdjustedAlignment() < PINKISH || getAdjustedAlignment() > BLUISH) {
				multiplier /= 2;
				print("Your dissonance with earth reduces your damage.\n");
			}
		} else {
			if(getAlignment() < 0) {
				multiplier /= 2;
				print("Your evilness reduces your damage.\n");
			}
		}
	}
	if(cClass == DEATHKNIGHT) {
		if(getAdjustedAlignment() > NEUTRAL) {
			multiplier /= 2;
			print("Your goodness reduces your damage.\n");
		}
	}

	// Bonus spread out over entire series of attack for multi attack weapons
	if(computeBonus) {
		if(cClass == PALADIN) {
			int goodDmg = mrand(1, 1 + level / 3);
			if(deity == GRADIUS) {
				if(alignInOrder() && victim->getRace() != DWARF && victim->getDeity() != GRADIUS) {
					bonusDamage.add(goodDmg);
					print("Your attunement with earth increased your damage by %d.\n", goodDmg);
				}
			} else {
				if(getAdjustedAlignment() >= BLUISH && victim->getAlignment() <= 0) {
					bonusDamage.add(goodDmg);
					print("Your goodness increased your damage by %d.\n", goodDmg);
				}
			}
		}
		if(cClass == DEATHKNIGHT) {
			// Only drain on 1st attack if a multi weapon
			if(getAdjustedAlignment() <= REDDISH && victim->getAdjustedAlignment() >= NEUTRAL)
				drain = mrand(1, 1 + level / 3);
		}
		if(	(	cClass == BERSERKER ||
				(cClass == CLERIC && deity == ARES) ||
				isStaff()
			) &&
			isEffected("berserk"))
		{
			// Only do a bonus if not a multi weapon, or is a multi weapon and it's the first attack
			if(weapon && weaponCategory != "ranged")
				bonusDamage.add((int)(attackDamage.get()/2));
		}

		if(	(	(cClass == DEATHKNIGHT && getAdjustedAlignment() <= REDDISH) ||
				(cClass == PALADIN && getAdjustedAlignment() == ROYALBLUE)
			) &&
			(isEffected("pray") || isEffected("dkpray"))
		)
			bonusDamage.add(mrand(1,3));

		if((isEffected("lycanthropy") || isCt()) && isEffected("frenzy"))
			bonusDamage.add(mrand(3,5));

		if((cClass == MONK || isCt()) && flagIsSet(P_FOCUSED))
			bonusDamage.add(mrand(1,3));
	}



	// If this is a monk, and we're not wielding a monk weapon
	// Or this is a werewolf, and we're not wielding a werewolf weapon or a claw weapon****
	//	**** Although I'm pretty sure werewolves can only use claw weapons now...but put here
	//		in case this changes in the future
	if(attackType != ATTACK_KICK && (cClass == MONK || isEffected("lycanthropy"))) {
		if(	weapon && (
				(cClass == MONK && !weapon->flagIsSet(O_SEL_MONK)) ||
				(isEffected("lycanthropy") && (
					!weapon->flagIsSet(O_SEL_WEREWOLF) ||
					weapon->getWeaponType() != "claw")
				)
			)
		) {
			if(cClass == MONK)
				print("How can you attack well with your hands full?\n");
			else
				print("How can you attack well with your paws full?\n");
			multiplier /= 2;
		}
	}

	if(multiplier > 0.0) {
		attackDamage.set((int)((float)(attackDamage.get() * multiplier)));
		if(computeBonus) {
			if(attackType != ATTACK_BACKSTAB)
				bonusDamage.set((int)((float)bonusDamage.get() * multiplier));
//			else
//				bonus = static_cast<int>(static_cast<float>(bonus) * (multiplier/2.0));
		}
	}


	if(result == ATTACK_CRITICAL) {
		int mult=0;
		char atk[25];
		switch(attackType) {
			case ATTACK_BASH:
				strcpy(atk, "bash");
				break;
			case ATTACK_KICK:
				strcpy(atk, "kick");
				break;
			default:
				strcpy(atk, "hit");
				break;
		}

		printColor("^gCRITICAL %s!\n", atk);
		broadcast(getSock(), getRoomParent(), "^g%M made a critical %s.", this, atk);
		mult = mrand(3, 5);
		attackDamage.set(attackDamage.get() * mult);
		drain *= mult;
		// We'll go with the assumption that if you critical on the first hit, the remaining
		// ones in that series will hurt a little more, so this will work just fine
		// if the first of a series of hits is a critical
		if(computeBonus)
			bonusDamage.set(bonusDamage.get() * mult);
		broadcastGroup(false, victim, "^g%M made a critical %s!\n", this, atk);
		if(	attackType != ATTACK_KICK && weapon && !isDm() && (
				weapon->flagIsSet(O_ALWAYS_CRITICAL) ||
				(	!weapon->flagIsSet(O_NEVER_SHATTER) &&
					!weapon->flagIsSet(O_STARTING) &&
					// using half-percentages here:
					// +0 = 3.5%, +1 = 2.5%, +2 = 1.5%, +3 = 0.5%
					mrand(1, 200) <= (7 - weapon->getAdjustment()*2)
				)
			)
		) {
			printColor("^YYour %s shatters.\n", weapon->getCName());
			broadcast(getSock(), getRoomParent(),"^Y%s %s shattered.", upHisHer(), weapon->getCName());
			retVal = 1;
		}
	} else if(result == ATTACK_GLANCING) {
		printColor("^CYou only managed to score a glancing blow!\n");
		broadcast(getSock(), getRoomParent(), "^C%M scored a glancing blow!", this);
		if(mrand(1,2)) {
			attackDamage.set(attackDamage.get() / 2);
			drain /= 2;
			if(computeBonus)
				bonusDamage.set(bonusDamage.get() / 2);
		} else {
			attackDamage.set(attackDamage.get() * 2 / 3);
			drain = (drain * 2) / 3;
			if(computeBonus)
				bonusDamage.set(bonusDamage.get() * 2 / 3);
		}

	} else if(result == ATTACK_BLOCK) {
		attackDamage.set(victim->computeBlock(attackDamage.get()));
		if(computeBonus)
			bonusDamage.set(victim->computeBlock(bonusDamage.get()));
	}

	victim->modifyDamage(this, PHYSICAL, attackDamage, NO_REALM, weapon, 0, computeBonus ? OFFGUARD_NOREMOVE : OFFGUARD_REMOVE);

	// Don't forget to modify the bonus
	if(computeBonus) {
		// Make bonus proportional to weapon speed, otherwise it's too much with fast weapons, and
		// too little with slow weapons.  (Bonus / 3) * weapon speed
		bonusDamage.set((int)(((float)bonusDamage.get()/(float)DEFAULT_WEAPON_DELAY) * weapon->getWeaponDelay()));

		victim->modifyDamage(this, PHYSICAL, bonusDamage, NO_REALM, weapon, 0, OFFGUARD_NOPRINT, true);
		attackDamage.setBonus(bonusDamage);
	}

	if(retVal != 1) {
		// If we didn't shatter, minimum of 1 damage
		attackDamage.set(MAX(attackDamage.get(), 1));
	}

	return(retVal);
}

//**********************************************************************
//						computeDamage
//**********************************************************************

int Monster::computeDamage(Creature* victim, Object* weapon, AttackType attackType, AttackResult& result, Damage& attackDamage, bool computeBonus, int& drain, float multiplier) {
	Damage bonusDamage;

	if(computeBonus)
		bonusDamage.set(getBaseDamage());

	if(ready[WIELD-1])
		attackDamage.add(ready[WIELD-1]->damage.roll() + ready[WIELD-1]->getAdjustment());
	else
		attackDamage.add(damage.roll());

	attackDamage.add(::bonus(strength.getCur()));

	if(result == ATTACK_CRITICAL) {
		broadcast(NULL, getRoomParent(), "%M made a critical hit.", this);
		int mult = mrand(2, 5);
		attackDamage.set(attackDamage.get() * mult);
		drain *= mult;
		// No shatter for mobs :)
	}
	else if(result == ATTACK_BLOCK) {
		attackDamage.set(victim->computeBlock(attackDamage.get()));
		if(computeBonus) {
			bonusDamage.set(victim->computeBlock(bonusDamage.get()));
		}
	}

	victim->modifyDamage(this, PHYSICAL, attackDamage);
	victim->modifyDamage(this, PHYSICAL, bonusDamage);
	attackDamage.setBonus(bonusDamage);

	attackDamage.set(MAX(1, attackDamage.get()));
	return(0);
}

//**********************************************************************
//						computeBlock
//**********************************************************************

int Creature::computeBlock(int dmg) {
	// TODO: Tweak amount of blockage based on the shield
	// for now, just half the damage
	dmg /= 2;
	return(dmg);
}

//**********************************************************************
//						dodge
//**********************************************************************
// This function prints the messages for dodging, chance is now
// computed elsewhere

int Creature::dodge(Creature* target) {
	int		i = mrand(1,10);

	unhide();
	smashInvis();

	if(isPlayer()) {
	    Player* player = getAsPlayer();
		player->statistics.dodge();
		player->increaseFocus(FOCUS_DODGE);
	}

	if(target->isPlayer())
		target->getAsPlayer()->statistics.miss();

	if(i == 1) {
		printColor("^cYou barely manage to dodge %N's attack.\n", target);
		broadcast(getSock(), target->getSock(), getRoomParent(),
			"%M barely dodges %N's attack.", this, target);
		if(target->isPlayer())
			target->printColor("^c%M somehow manages to dodge your attack.\n", this);
	} else if(i == 2) {
		printColor("^cYou deftly dodge %N's attack.\n", target);
		broadcast(getSock(), target->getSock(), getRoomParent(),
			"%M deftly dodges %N's attack.", this, target);
		if(target->isPlayer())
			target->printColor("^c%M deftly dodges your attack.\n", this);
	} else if(i == 3 && (target->isPlayer())) {
		printColor("^cYou side-step %N's attack and smack %s on the back of the head.\n", target,
			target->himHer());
		broadcast(getSock(), target->getSock(), getRoomParent(),
			"%M side-steps %N's attack and smacks %s on the back of the head.", this,
			target, target->himHer());
		if(target->isPlayer())
			target->printColor("^c%M side-steps your attack and smacks you on the back of the head.\n", this);
	} else if(i > 3 && i < 6) {
		printColor("^cYou dance gracefully around %N's attack.\n", target);
		broadcast(getSock(), target->getSock(), getRoomParent(),
			"%M dances gracefully around %N's attack.", this, target);
		if(target->isPlayer())
			target->printColor("^c%M dances gracefully around your attack.\n", this);
	} else if(i >= 6 && i < 8) {
		printColor("^cYou easily dodge %N's attack.\n", target);
		broadcast(getSock(), target->getSock(), getRoomParent(),
			"%M easily dodges %N's attack.", this, target);
		if(target->isPlayer())
			target->printColor("^c%M easily dodges your attack.\n",this);
	}
	else if(i >= 8 && i < 9) {
		printColor("^cYou easily duck under %N's pitifully executed attack.\n", target);
		broadcast(getSock(), target->getSock(), getRoomParent(),
			"%M easily ducks under %N's pitifully executed attack.", this, target);
		if(target->isPlayer())
			target->printColor("^c%M easily ducks under your pitifully executed attack.\n",this);
	} else if(i >= 9 && i <= 10) {
		printColor("^cYou laugh at %N as you easily dodge %s attack.\n",
			target, target->hisHer());
		broadcast(getSock(), target->getSock(), getRoomParent(),
			"%M laughs as %s easily dodges %N's attack.", this, heShe(), target);
		if(target->isPlayer())
			target->printColor("^c%M laughs as %s dodges your attack.\n", this, heShe());
	} else {
		printColor("^cYou deftly dodge %N's attack.\n", target);
		broadcast(getSock(), target->getSock(), getRoomParent(),
			"%M deftly dodges %N's attack.", this, target);
		if(target->isPlayer())
			target->printColor("^c%M deftly dodges your attack.\n",this);
	}


	return(1);
}

//**********************************************************************
//						canRiposte
//**********************************************************************

bool Creature::canRiposte() const {
	if(isPlayer())
		return(true);
	if(flagIsSet(M_CAN_RIPOSTE))
		return(true);
	return(level >= 15 && (
		cClass == FIGHTER ||
		cClass == BERSERKER ||
		cClass == ASSASSIN ||
		cClass == THIEF ||
		cClass == ROGUE
	));
}

//*********************************************************************
//						parry
//*********************************************************************
// This function allows a creature to either parry a blow, or to
// strike back after parry. It was made for the Rogue class. -- TC
// Returns 2 on death of person being reposited, returns 1 on non-death sucess
// This is only called when success has already been determined

int Creature::parry(Creature* target) {
	long	t=0;
	Object*	weapon = ready[WIELD-1];
	Damage attackDamage;

	if(!weapon && isPlayer()) {
		broadcast(::isDm, "*** Parry error: called with null weapon for %s.\n", getCName());
		return(0);
	}

	t = time(0);
	//i = LT(this, LT_RIPOSTE);

	if(isPlayer()) {
		t=time(0);
		lasttime[LT_RIPOSTE].ltime = t;

		switch(cClass) {
		case THIEF:
		case ASSASSIN:
		case FIGHTER:
			lasttime[LT_RIPOSTE].interval = 9L;
			break;

		default:
			lasttime[LT_RIPOSTE].interval = 6L;
			break;
		}
	}
	if(isMonster()) {
		unhide();
		smashInvis();
	}

	// If we get a hit, it's a riposte, otherwise just a parry
	AttackResult result;


	// If we're a player, or a monster that's over 15 and is a certain class,
	// we have a chance to riposte, otherwise only do a parry
	if(canRiposte())
		result = getAttackResult(target, weapon, DOUBLE_MISS|NO_DODGE|NO_PARRY|NO_BLOCK|NO_CRITICAL|NO_FUMBLE|NO_GLANCING);
	else
		result = ATTACK_MISS; // Parry


	//checkImprove("parry", true);

	// if result == miss || can't hit target, parry
	if(result == ATTACK_MISS || !canHit(target, weapon, true, false)) {
		printColor("^cYou parry %N's attack.\n", target);
		broadcast(getSock(), target->getSock(), getRoomParent(), "%M parries %N's attack.", this, target);
		if(target->isPlayer())
			target->printColor("^c%M parries your attack.\n", this);
		if(isPlayer()) {
		    getAsPlayer()->increaseFocus(FOCUS_PARRY);
		}
	} else {
		// We have a riposte, calculate damage and such
		bstring verb = weapon->getWeaponVerb();
		bstring verbPlural = weapon->getWeaponVerbPlural();
		int drain=0;
		bool wasKilled = false, freeTarget = false, meKilled = false;
		//int enchant = 0;
		//if(weapon)
		//	enchant = abs(weapon->adjustment);

		computeDamage(target, weapon, ATTACK_NORMAL, result, attackDamage, true, drain);
		attackDamage.add(attackDamage.getBonus());

		// So mob riposte isn't soo mean
		if(isMonster()) {
			attackDamage.set(attackDamage.get() / 2);
			attackDamage.set(MAX(1, attackDamage.get()));
		}

		switch(mrand(1,7)) {
		case 1:
			printColor("^cYou side-step ^M%N's^c attack and %s %s for %s%d^c damage.\n",
					target, verb.c_str(), target->himHer(), customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			broadcast(getSock(), target->getSock(), getRoomParent(), "%M side-steps %N's attack and %s %s.",
				this, target, verbPlural.c_str(), target->himHer());
			if(target->isPlayer())
				target->printColor("^M%M^x side-steps your attack and %s you for %s%d^x damage.\n",
					this, verbPlural.c_str(), target->customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			break;
		case 2:
			printColor("^cYou lunge and viciously %s ^M%N^c for %s%d^c damage.\n",
				verb.c_str(), target, customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			broadcast(getSock(), target->getSock(), getRoomParent(), "%M lunges and viciously %s %N.",
				this, verbPlural.c_str(), target );
			if(target->isPlayer())
				target->printColor("^M%M^x lunges at you and viciously %s you for %s%d^x damage.\n",
					this, verbPlural.c_str(), target->customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			break;
		case 3:
			printColor("^cYou slide around ^M%N's^c attack and %s %s for %s%d^c damage.\n",
				target, verb.c_str(), target->himHer(), customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			broadcast(getSock(), target->getSock(), getRoomParent(), "%M slides around %N's attack and %s %s.",
				this, target, verbPlural.c_str(), target->himHer());
			if(target->isPlayer())
				target->printColor("^M%M^x slides around your attack and %s you for %s%d^x damage.\n",
					this, verbPlural.c_str(), target->customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			break;
		case 4:
			printColor("^cYou spin away from ^M%N^c's attack and %s %s for %s%d^c damage.\n",
				target, verb.c_str(), target->himHer(), customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			broadcast(getSock(), target->getSock(), getRoomParent(), "%M spins away from %N's attack and %s %s.",
				this, target, verbPlural.c_str(), target->himHer());
			if(target->isPlayer())
				target->printColor("^M%M^x spins away from your attack and %s you for %s%d^x damage.\n",
					this, verbPlural.c_str(), target->customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			break;
		case 5:
			printColor("^cYou duck under ^M%N's^c attack and %s %s for %s%d^c damage.\n",
				target, verb.c_str(), target->himHer(), customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			broadcast(getSock(), target->getSock(), getRoomParent(), "%M ducks under %N's attack and %s %s.",
				this, target, verbPlural.c_str(), target->himHer() );
			if(target->isPlayer())
				target->printColor("^M%M^x ducks under your attack and %s you for %s%d^x damage.\n",
					this, verbPlural.c_str(), target->customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			break;
		case 6:
			printColor("^cYou laugh at ^M%N^c and quickly %s %s for %s%d^c damage.\n",
				target, verb.c_str(), target->himHer(), customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			broadcast(getSock(), target->getSock(), getRoomParent(), "%M laughs at %N and quickly %s %s.",
				this, target, verbPlural.c_str(), target->himHer() );
			if(target->isPlayer())
				target->printColor("^M%M^x laughs at you and quickly %s you for %s%d^x damage.\n",
					this, verbPlural.c_str(), target->customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			break;
		case 7:
			printColor("^cYou riposte ^M%N's^c attack and %s %s for %s%d^c damage.\n",
				target, verb.c_str(), target->himHer(), customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			broadcast(getSock(), target->getSock(), getRoomParent(), "%M ripostes %N's attack and %s %s.",
				this, target, verbPlural.c_str(), target->himHer() );
			if(target->isPlayer())
				target->printColor("^M%M^x ripostes your attack and %s you for %s%d^x damage.\n",
					this, verbPlural.c_str(), target->customColorize("*CC:DAMAGE*").c_str(), attackDamage.get());
			break;
		}
		if(weapon) {
			if(!mrand(0, 3))
				weapon->decShotsCur();

			// die check moved right before return.
			if(weapon->getShotsCur() <= 0) {
				printColor("%O just broke.\n", weapon);
				broadcast(getSock(), target->getSock(), getRoomParent(), "%M's just broke %P.", this, weapon);
				unequip(WIELD);
			}
		}

		if(target->isPlayer()) {
			Player* pCrt = target->getAsPlayer();
			pCrt->updateAttackTimer();
		}

		if(isPlayer()) {
            getAsPlayer()->increaseFocus(FOCUS_RIPOSTE, attackDamage.get(), target);
        }



		meKilled = doReflectionDamage(attackDamage, target);

		if(	doDamage(target, attackDamage.get(), CHECK_DIE, PHYSICAL_DMG, freeTarget) ||
			wasKilled ||
			meKilled)
		{
			Creature::simultaneousDeath(this, target, false, freeTarget);
			return(2);
		}
	}

	return(1);
}

//**********************************************************************
//						autoAttackEnabled
//**********************************************************************

bool Player::autoAttackEnabled() const {
	return(!flagIsSet(P_NO_AUTO_ATTACK));
}

//**********************************************************************
//						setFleeing
//**********************************************************************

void Player::setFleeing(bool pFleeing) {
	fleeing = pFleeing;
}

//**********************************************************************
//						autoAttackEnabled
//**********************************************************************

bool Player::isFleeing() const {
	return(fleeing);
}

//*********************************************************************
//						isHidden
//*********************************************************************

bool Creature::isHidden() const {
	return(flagIsSet(isPlayer() ? P_HIDDEN : M_HIDDEN));
}

//*********************************************************************
//						negAuraRepel
//*********************************************************************

bool Creature::negAuraRepel() const {
	return(cClass == LICH && !isEffected("resist-magic"));
}

//*********************************************************************
//						doResistMagic
//*********************************************************************

int Creature::doResistMagic(int dmg, Creature* enemy) {
	float resist=0;
	dmg = MAX(1, dmg);

	if(negAuraRepel() && enemy && this != enemy) {
		resist = (10 + mrand(1,3) + level + bonus((int) constitution.getCur()))
			- (bonus((int)enemy->intelligence.getCur()) + bonus((int)enemy->piety.getCur()));
		resist /= 100; // percentage
		resist *= dmg;
		dmg -= (int)resist;
	}

	if(isEffected("resist-magic")) {
		resist = (piety.getCur() / 10 + intelligence.getCur() / 10) * 2;
		resist = MAX(50, MIN(resist, 100));
		resist /= 100; // percentage
		resist *= dmg;
		dmg -= (int)resist;
	}

	return(MAX(0, dmg));
}

//*********************************************************************
//						updateAttackTimer
//*********************************************************************

void Creature::updateAttackTimer(bool setDelay, int delay) {
	if(!setDelay) {
		attackTimer.update();
	} else {
		if(delay != 0)
			attackTimer.update(delay);
		else {
			if(ready[HELD-1] && ready[HELD-1]->getWearflag() == WIELD)
				attackTimer.update(MAX(ready[WIELD-1]->getWeaponDelay(), ready[HELD-1]->getWeaponDelay()));
			else
				attackTimer.update(ready[WIELD-1]->getWeaponDelay());
		}
	}
}

//*********************************************************************
//						getAttackDelay
//*********************************************************************

int Creature::getAttackDelay() const {
	return(attackTimer.getDelay());
}

//*********************************************************************
//						checkAttackTimer
//*********************************************************************
// Return: true if the attack timer has expired, false if not

bool Creature::checkAttackTimer(bool displayFail) {
	long i;
	if(!((i = attackTimer.getTimeLeft()) == 0) && !isDm()) {
		if(displayFail)
			pleaseWait(i/10.0);
		return(false);
	}
	return(true);
}

//*********************************************************************
//						modifyAttackDelay
//*********************************************************************

void Creature::modifyAttackDelay(int amt) {
	attackTimer.modifyDelay(amt);
}

//*********************************************************************
//						setAttackDelay
//*********************************************************************

void Creature::setAttackDelay(int newDelay) {
	attackTimer.setDelay(newDelay);
}

//*********************************************************************
//						pleaseWait
//*********************************************************************

void Creature::pleaseWait(long duration) const {
	if(duration < 0)
		duration *= -1;
	if(duration == 1)
		print("Please wait 1 more second.\n");
	else if(duration > 60)
		print("Please wait %d:%02d minutes.\n", duration / 60L, duration % 60L);
	else
		print("Please wait %d more seconds.\n", duration);
}

void Creature::pleaseWait(int duration) const {
	pleaseWait((long)duration);
}

void Creature::pleaseWait(double duration) const {
	// Floating point equality is unreliable
	if(!(duration > 1) && !(duration < 1))
		print("Please wait 1.0 more second.\n");
	else
		print("Please wait %.1f more seconds.\n", duration);
}

//*********************************************************************
//						getLTAttack
//*********************************************************************

time_t Creature::getLTAttack() const {
	return(attackTimer.getLT());
}




/*			Web Editor
 * 			 _   _  ____ _______ ______
 *			| \ | |/ __ \__   __|  ____|
 *			|  \| | |  | | | |  | |__
 *			| . ` | |  | | | |  |  __|
 *			| |\  | |__| | | |  | |____
 *			|_| \_|\____/  |_|  |______|
 *
 * 		If you change anything here, make sure the changes are reflected in the web
 * 		editor! Either edit the PHP yourself or tell Dominus to make the changes.
 */

//*********************************************************************
//						getTypeModifier
//*********************************************************************

float Object::getTypeModifier() const {
	bstring armorType = getArmorType();

	if(armorType == "plate" || armorType == "shield")
		return(42.89);
	else if(armorType == "chain")
		return(34.14);
	else if(armorType == "leather")
		return(24.46);
	else if(armorType == "cloth")
		return(12.25);
	else
		return(0.00);

	 //Cloth-> Crayola sent, "how about 15.04, corresponding to 45%?"
}

//*********************************************************************
//						getLocationModifier
//*********************************************************************

float Object::getLocationModifier() const {
	switch(wearflag) {
		case BODY:
			return(0.24);
		case ARMS:
			return(0.08);
		case LEGS:
			return(0.12);
		case NECK:
			return(0.08);
		case BELT:
			return(0.06);
		case HANDS:
			return(0.04);
		case HEAD:
			return(0.08);
		case FEET:
			return(0.06);
		case FINGER:
			return(0.00);
		case SHIELD:
			return(0.12);
		case FACE:
			return(0.08);
//		case BRACER:
//			return(0.04);
		default:
			return(0.00);
	}
}

//*********************************************************************
//						adjustArmor
//*********************************************************************

int Object::adjustArmor() {
	if(type != ARMOR || quality <= 0 || wearflag == WIELD || wearflag == FINGER)
		return(-1);

	return(armor = (short)(getTypeModifier() * ((quality/10.0) + 2.3525) * getLocationModifier()));
}

//*********************************************************************
//						adjustWeapon
//*********************************************************************

int Object::adjustWeapon() {
	if(type != WEAPON || quality <= 0 || wearflag != WIELD) {
		damage.setMean(0);
		return(-1);
	}

	// Quality for weapons directly affects damage. If any of these factors change,
	// we need to readjust quality.
	//  attack delay
	//  numAttacks

	// For a given quality, convert to damage-per-second
	double dps = (quality / 11.4 + 5) / 2.6;
	short num = (numAttacks ? numAttacks : 1);

	// For a given damage-per-second, convert it to average damage.
	// This is the equation from Object::statObj backwards.
	double avg = ((getWeaponDelay()/10.0) * dps) / ((1.0 + num) / 2.0);

	// Set the average damage for this weapon
	damage.clear();
	damage.setMean(avg);

	return(avg);
}