roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * weaponless.c
 *   Functions that deal with weaponless 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-2009 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 "commands.h"

//*********************************************************************
//						cmdMeditate
//*********************************************************************

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

	player->clearFlag(P_AFK);

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

	if(!player->knowsSkill("meditate") || player->isUndead()) {
		player->print("You meditate.\n");
		broadcast(player->getSock(), player->getRoom(), "%M meditates.", player);
		return(0);
	}

	i = player->lasttime[LT_MEDITATE].ltime + player->lasttime[LT_MEDITATE].interval;
	if(i>t && !player->isCt()) {
		player->pleaseWait(i-t);
		return(0);
	}

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

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

	double level = player->getSkillLevel("meditate");

	broadcast(player->getSock(), player->getRoom(), "%M meditates.", player);

	if(mrand(1,100) <= chance) {
		player->print("You feel at one with the universe.\n");
		player->checkImprove("meditate", true);

		// new meditate
		player->hp.increase(MAX(0,((int)(level/3)
					+ mrand(1,(int)(level))
					+ bonus((int)player->constitution.getCur())*mrand(1,4))));

		// old meditate: player->hp.getCur() += mrand(4,15)+player->getLevel();

		player->lasttime[LT_MEDITATE].ltime = t;
		player->lasttime[LT_MEDITATE].interval = 90L;
	} else {
		player->print("Your spirit is not at peace.\n");
		player->checkImprove("meditate", false);
		player->lasttime[LT_MEDITATE].ltime = t;
		player->lasttime[LT_MEDITATE].interval = 5L;
	}

	return(0);

}


//*********************************************************************
//						cmdTouchOfDeath
//*********************************************************************
// This function allows monks to kill nonundead creatures.
// If they succeed then the creature is either killed or harmed
// for approximately half of its hit points.

int cmdTouchOfDeath(Player* player, cmd* cmnd) {
	Creature* creature=0;
	Player	*pCreature=0;
	long	i=0, t=0;
	int		chance=0;
	Damage damage;

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

	if(cmnd->num < 2) {
		player->print("Touch whom?\n");
		return(0);
	}

	if(!player->knowsSkill("touch")) {
		player->print("You touch yourself.\n");
		broadcast(player->getSock(), player->getRoom(), "%M touches %sself", player, player->himHer());
		return(0);
	}

	if(player->ready[WIELD-1] && !player->isDm() && !player->ready[WIELD-1]->flagIsSet(O_ALLOW_TOUCH_OF_DEATH)) {
		player->print("How can you do that with your hands full?\n");
		return(0);
	}
	creature = player->getRoom()->findCreature(player, cmnd->str[1], cmnd->val[1], true, true);
	if(creature)
		pCreature = creature->getPlayer();
	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->isUndead() &&
		!player->checkStaff("That wont work on the undead.\n") )
	{
		if(!pCreature)
			creature->getMonster()->addEnmCrt(player);
		return(0);
	}


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

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

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

	if(pCreature) {

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

	player->updateAttackTimer(false);
	player->lasttime[LT_TOUCH_OF_DEATH].ltime = t;
	player->lasttime[LT_TOUCH_OF_DEATH].interval = 600L;

	if(player->isDm())
		player->lasttime[LT_TOUCH_OF_DEATH].interval = 0;


	chance = (int)((player->getSkillLevel("touch") - creature->getLevel())*20)+bonus((int)player->constitution.getCur())*10;
	chance = MIN(chance, 85);

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

	if(creature->flagIsSet(M_RESIST_TOUCH) && creature->isMonster() && !player->isCt())
		chance = 0;

	if(creature->isPlayer() && creature->flagIsSet(P_BERSERKED))
		chance /= 2;

	if(mrand(1,100) > chance) {
		player->print("You failed to harm %N.\n", creature);
		player->checkImprove("touch", false);
		broadcast(player->getSock(), player->getRoom(), "%M failed the touch of death on %N.\n",
			player, creature);
		return(0);
	}


	if(!player->isCt()) {
		if(creature->chkSave(DEA, player, 0)) {
			player->printColor("^y%M avoided your touch of death!\n", creature);
			player->checkImprove("touch", false);
			creature->print("You avoided %N's touch of death.\n", player);
			return(0);
		}
	}

	if(((mrand(1,100) > 80 - bonus((int)player->constitution.getCur())) && ((creature->isMonster()
	        && !creature->flagIsSet(M_PERMENANT_MONSTER)) || creature->isPlayer())) || player->isDm()) {
		player->print("You fatally wound %N.\n", creature);
		player->checkImprove("touch", true);
		if(!player->isDm())
			log_immort(false,player, "%s fatally wounds %s.\n", player->name, creature->name);

		broadcast(player->getSock(), player->getRoom(), "%M fatally wounds %N.", player, creature);
		if(creature->isMonster())
			creature->getMonster()->addEnmDmg(player, creature->hp.getCur());
		//player->statistics.attackDamage(creature->hp.getCur(), "touch-of-death");
		creature->die(player);

	} else {

		damage.set(MAX(1, creature->hp.getCur() / 2));

		creature->modifyDamage(player, ABILITY, damage);
		//player->statistics.attackDamage(dmg, "touch-of-death");

		player->printColor("You touched %N for %s%d^x damage.\n", creature, player->customColorize("*CC:DAMAGE*"), damage.get());
		player->checkImprove("touch", true);
		broadcast(player->getSock(), player->getRoom(), "%M uses the touch of death on %N.", player, creature);
		if(player->getClass() == CARETAKER)
			log_immort(false,player, "%s uses the touch of death on %s.\n", player->name, creature->name);
		if(player->doDamage(creature, damage.get(), CHECK_DIE)) {
			if(player->getClass() == CARETAKER)
				log_immort(false,player, "%s killed %s with touch of death.\n", player->name, creature->name);
		}
	}

	return(0);
}

//*********************************************************************
//						cmdFocus
//*********************************************************************

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

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

	if(!player->knowsSkill("focus")) {
		player->print("You try to focus on inner peace but fail.\n");
		return(0);
	}

	if(player->flagIsSet(P_FOCUSED)) {
		player->print("You've already focused your energy.\n");
		return(0);
	}

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

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

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

	if(player->flagIsSet(P_PRAYED))
		chance += 10;

	if(mrand(1, 100) <= chance) {
		player->print("You begin to focus your energy.\n");
		player->checkImprove("focus", true);
		broadcast(player->getSock(), player->getRoom(), "%M focuses %s energy.", player, player->hisHer());
		player->setFlag(P_FOCUSED);
		player->lasttime[LT_FOCUS].ltime = t;
		player->lasttime[LT_FOCUS].interval = 210L;

		player->computeAttackPower();
	} else {
		player->print("You failed to focus your energy.\n");
		player->checkImprove("focus", false);
		broadcast(player->getSock(), player->getRoom(), "%M tried to focus %s energy.",
			player, player->hisHer());
		player->lasttime[LT_FOCUS].ltime = t - 590L;
	}

	return(0);

}


//*********************************************************************
//						cmdFrenzy
//*********************************************************************
// This command allows a werewolf to attack in a frenzy (every 2 seconds
// instead of 3) and get an extra 5 dex.

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

	player->clearFlag(P_AFK);

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

	if(!player->knowsSkill("frenzy")) {
		player->print("You try to work yourself up into a frenzy but fail.\n");
		return(0);
	}
	if(!player->isEffected("lycanthropy") && !player->isStaff()) {
		player->print("Only werewolves may go into a frenzy.\n");
		return(0);
	}

	if(player->flagIsSet(P_FRENZY)) {
		player->print("You're already in a frenzy.\n");
		return(0);
	}
	if(player->flagIsSet(P_SITTING)) {
		player->print("You have to be standing to frenzy.\n");
		return(0);
	}

	if(player->isEffected("haste")) {
		player->print("Your magically enhanced speed prevents you from going into a frenzy.\n");
		return(0);
	}
	if(player->isEffected("slow")) {
		player->print("Your magically reduced speed prevents you from going into a frenzy.\n");
		return(0);
	}


	if(player->ready[WIELD - 1]) {
		player->print("You cannot frenzy while wielding something.\n");
		return(0);

	}


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

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

	chance = MIN(85, (int)(player->getSkillLevel("frenzy") * 20) + bonus((int) player->dexterity.getCur()));

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

	if(mrand(1, 100) <= chance) {
		player->print("You begin to attack in a frenzy.\n");
		player->checkImprove("frenzy", true);
		broadcast(player->getSock(), player->getRoom(), "%M attacks in a frenzy.", player);
		player->setFlag(P_FRENZY);
		player->dexterity.addCur(50);
		player->lasttime[LT_FRENZY].ltime = t;
		player->lasttime[LT_FRENZY].interval = 210L;
	} else {
		player->print("Your attempt to frenzy failed.\n");
		player->checkImprove("frenzy", false);
		broadcast(player->getSock(), player->getRoom(), "%M tried to attack in a frenzy.", player);
		player->lasttime[LT_FRENZY].ltime = t - 590L;
	}

	return(0);
}

//*********************************************************************
//						cmdMaul
//*********************************************************************
// This function allows werewolves to "maul" 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 cmdMaul(Player* player, cmd* cmnd) {
	Creature* creature=0;
	Player	*pCreature=0;
	long	i=0, t=0;
	int		chance=0, not_initial=0;

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

	if(cmnd->num < 2) {
		player->print("Maul whom?\n");
		return(0);
	}

	if(!player->knowsSkill("maul")) {
		player->print("You simply don't know how to maul anyone!\n");
		return(0);
	}
	if(!player->isEffected("lycanthropy") && !player->isStaff()) {
		player->print("Only werewolves may maul people.\n");
		return(0);
	}

	creature = player->getRoom()->findCreature(player, cmnd);
	if(creature)
		pCreature = creature->getPlayer();
	if(!creature || creature == player || (pCreature && strlen(cmnd->str[1]) < 3)) {
		player->print("That isn't here.\n");
		return(0);
	}

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

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

		i = LT(player, LT_MAUL);
		t = time(0);
		if(i > t) {
			player->pleaseWait(i - t);
			return(0);
		}
	}


	if(!player->isCt() && pCreature) {
		if(pCreature->flagIsSet(P_MISTED)) {
			player->print("You cannot physically hit a misted vampire.\n");
			return(0);
		}

		if(player->vampireCharmed(pCreature) || (pCreature->hasCharm(player->name) && player->flagIsSet(P_CHARMED))) {
			player->print("You like %N too much to do that.\n", pCreature);
			return(0);
		}
	}



	player->unhide();
	player->smashInvis();
	if(player->ready[WIELD - 1]) {
		player->print("How can you do that with your claws full?\n");
		return(0);
	}

	player->lasttime[LT_MAUL].ltime = t;
	if(creature->isMonster())
		player->lasttime[LT_MAUL].interval = 15L;
	else
		player->lasttime[LT_MAUL].interval = 3L;

	player->updateAttackTimer(true, DEFAULT_WEAPON_DELAY);
	player->lasttime[LT_SPELL].ltime = t;
	player->lasttime[LT_SPELL].interval = 3;
	player->lasttime[LT_READ_SCROLL].ltime = t;
	player->lasttime[LT_READ_SCROLL].interval = 3;

	if(!pCreature) {

		creature->getMonster()->addEnmCrt(player);

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

		if(!player->isCt() && creature->flagIsSet(M_ONLY_HARMED_BY_MAGIC)) {
			player->print("Your maul has no effect on %N.\n", creature);
			return(0);
		}

	}
	double level = player->getSkillLevel("maul");
	chance = 45 + (int)((level - creature->getLevel()) * 5) +
	         bonus((int) player->strength.getCur()) * 3 + (bonus((int) player->dexterity.getCur())
	                 - bonus((int) creature->dexterity.getCur())) * 2;

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

	if((creature->flagIsSet(M_ENCHANTED_WEAPONS_ONLY) || creature->flagIsSet(M_PLUS_TWO) || creature->flagIsSet(M_PLUS_THREE)) && (not_initial==1)) {
		chance /= 2;
		chance = MIN(chance, 50);
	}

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

	if(mrand(1, 100) > player->getLuck() + (int)(level * 2))
		chance = 5;

	if(mrand(1, 100) <= chance) {
		player->attackCreature(creature, ATTACK_MAUL);
		if(!induel(player, pCreature)) {
			// 5% chance to get lycanthropy when mauled by a werewolf
			creature->addLycanthropy(player, 5);
		}
	} else {
		player->print("You failed to maul %N.\n", creature);
		player->checkImprove("maul", false);
		creature->print("%M tried to maul you.\n", player);
		broadcast(player->getSock(), creature->getSock(), creature->getRoom(),
			"%M tried to maul %N.", player, creature);
	}

	return(0);
}


//*********************************************************************
//						packBonus
//*********************************************************************

int Player::packBonus() {
	Creature *leader = following ? following : this;
	ctag	*cp=0;
	int		bns=0;

	cp = leader->first_fol;
	while(cp) {
		// pack isn't pure
		if(!cp->crt->isEffected("lycanthropy") || cp->crt->isMonster())
			return(0);

		if(!cp->crt->inSameRoom(leader)) {
			cp = cp->next_tag;
			continue;
		}

		// bonus for all within 3 levels.
		if(cp->crt->isEffected("lycanthropy") && (abs((int)leader->getLevel() - (int)cp->crt->getLevel()) < 4))
			bns += mrand(1,2);

		cp = cp->next_tag;
	}

	return(MIN(10, bns));
}


//*********************************************************************
//						cmdHowl
//*********************************************************************

int cmdHowl(Creature* player, cmd* cmnd) {
	BaseRoom* room = player->getRoom();
	Monster *monster=0;
	ctag	*cp=0;
	long	i=0, t=0, stunTime=0;
	int		maxEffected=0, numEffected=0, bns=0;

	if(!player->canSpeak()) {
		player->print("You try to howl, but no sound comes forth!\n");
		return(0);
	}

	if((!player->knowsSkill("howl") || !player->isEffected("lycanthropy")) && !player->isStaff()) {
		player->print("You howl at the moon!\n");
		broadcast(player->getSock(), player->getRoom(), "%M howls at the moon.", player);
		return(0);
	}

	i = LT(player, LT_HOWLS);
	t = time(0);
	if(i > t && !player->isCt()) {
		player->pleaseWait(i-t);
		return(0);
	}

	if(numEnemyMonInRoom(player) < 1) {
		player->print("There are no enemies here for your howl to terrify.\n");
		return(0);
	}

	int level = (int)player->getSkillLevel("howl");
	room->wake("You awaken suddenly!", true);
	player->print("You let out a blood-curdling supernatural howl!\n");
	player->checkImprove("howl", true);
	broadcast(player->getSock(), room, "^Y%M lets out a blood-curdling supernatural howl!", player);
	maxEffected = (int)level / 2;

	player->lasttime[LT_HOWLS].ltime = t;
	player->lasttime[LT_HOWLS].interval = 240L; // every 4 minutes

	cp = room->first_mon;
	while(cp && numEffected < maxEffected) {
		monster = cp->crt->getMonster();
		cp = cp->next_tag;

		if(!monster || !monster->isEnmCrt(player->name))
			continue;
		if((int)level - monster->getLevel() < 6)
			continue;
		if(monster->isPet() || monster->getClass() == PALADIN)
			continue;

		numEffected++;


		bns = (int)(-10 * ((level-6) - monster->getLevel()));
		bns += monster->saves[MEN].chance*2;

		if(monster->isEffected("resist-magic"))
			bns += 50;

		// nothing happens if mob saves
		if(monster->chkSave(MEN, player, bns))
			continue;


		if( !monster->flagIsSet(M_DM_FOLLOW) &&
			!monster->flagIsSet(M_PERMENANT_MONSTER) &&
			!monster->flagIsSet(M_PASSIVE_EXIT_GUARD) &&
			mrand(1,100) <= 50
		) {
			if(monster->flee(true) == 2)
				continue;
			monster->stun(mrand(5,8));
			continue;
		}

		stunTime = mrand(5, MAX(6, player->getLevel()/2));
		monster->stun(stunTime);
		broadcast(NULL, room, "^b%M is frozen in terror!", monster);
		//	creature->addEnmCrt(player);
	}

	return(0);
}