/*
* weaponless.cpp
* 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-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 "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->getParent(), "%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;
int level = MAX(1,(int)player->getSkillLevel("meditate"));
broadcast(player->getSock(), player->getParent(), "%M meditates.", player);
if(mrand(1,100) <= chance) {
player->print("You feel at one with the universe.\n");
player->checkImprove("meditate", true);
// new meditate
int heal = (MAX(0,((int)(level/3)
+ mrand(1,(int)(level))
+ bonus((int)player->constitution.getCur())*mrand(1,4))));
player->doHeal(player, heal,1.0);
// 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(!player->knowsSkill("touch")) {
player->print("You touch yourself.\n");
broadcast(player->getSock(), player->getParent(), "%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);
}
if(!(creature = player->findVictim(cmnd, 1, true, false, "Use the touch of death on whom?\n", "You don't see that here.\n")))
return(0);
if(creature)
pCreature = creature->getAsPlayer();
if(!player->canAttack(creature))
return(0);
if(player->isBlind()) {
player->printColor("^CYou're blind!\n");
return(0);
}
if( creature->isUndead() &&
!player->checkStaff("That won't work on the undead.\n") )
{
if(!pCreature)
creature->getAsMonster()->addEnemy(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->getAsMonster()->addEnemy(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->mFlagIsSet(M_RESIST_TOUCH) && !player->isCt())
chance = 0;
if(creature->isPlayer() && creature->isEffected("berserk"))
chance /= 2;
if(mrand(1,100) > chance) {
player->print("You failed to harm %N.\n", creature);
player->checkImprove("touch", false);
broadcast(player->getSock(), player->getParent(), "%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->getCName(), creature->getCName());
broadcast(player->getSock(), player->getParent(), "%M fatally wounds %N.", player, creature);
if(creature->isMonster())
creature->getAsMonster()->adjustThreat(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*").c_str(), damage.get());
player->checkImprove("touch", true);
broadcast(player->getSock(), player->getParent(), "%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->getCName(), creature->getCName());
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->getCName(), creature->getCName());
}
}
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->isEffected("pray"))
chance += 10;
if(mrand(1, 100) <= chance) {
player->print("You begin to focus your energy.\n");
player->checkImprove("focus", true);
broadcast(player->getSock(), player->getParent(), "%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->getParent(), "%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->isEffected("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);
}
i = player->lasttime[LT_FRENZY].ltime;
t = time(0);
if(t - i < 600L && !player->isStaff()) {
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->getParent(), "%M attacks in a frenzy.", player);
player->addEffect("frenzy", 210L, 50);
player->lasttime[LT_FRENZY].ltime = t;
player->lasttime[LT_FRENZY].interval = 600 + 210L;
} else {
player->print("Your attempt to frenzy failed.\n");
player->checkImprove("frenzy", false);
broadcast(player->getSock(), player->getParent(), "%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(!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);
}
if(!(creature = player->findVictim(cmnd, 1, true, false, "Maul 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 && creature->getAsMonster()->isEnemy(player)) {
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->isEffected("mist")) {
player->print("You cannot physically hit a misted creature.\n");
return(0);
}
if(player->vampireCharmed(pCreature) || (pCreature->hasCharm(player->getName()) && player->flagIsSet(P_CHARMED))) {
player->print("You like %N too much to do that.\n", pCreature);
return(0);
}
}
player->unhide();
player->smashInvis();
//Wwolves can only wield claw weapons now...ok to maul with them. - TC
/* 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->getAsMonster()->addEnemy(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->getRoomParent(),
"%M tried to maul %N.", player, creature);
}
return(0);
}
//*********************************************************************
// packBonus
//*********************************************************************
int Player::packBonus() {
int bns=0;
Group* group = getGroup();
if(group) {
for(Creature* crt : group->members) {
// pack isn't pure
if(!crt->isEffected("lycanthropy") || crt->isMonster())
return(0);
if(!crt->inSameRoom(this)) continue;
// bonus for all within 3 levels.
if(crt->isEffected("lycanthropy") && (abs((int)getLevel() - (int)getLevel()) < 4))
bns += mrand(1,2);
}
}
return(MIN(10, bns));
}
//*********************************************************************
// cmdHowl
//*********************************************************************
int cmdHowl(Creature* player, cmd* cmnd) {
BaseRoom* room = player->getRoomParent();
Monster *monster=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->getParent(), "%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
MonsterSet::iterator mIt = room->monsters.begin();
while(mIt != room->monsters.end() && numEffected < maxEffected) {
monster = (*mIt++);
if(!monster || !monster->isEnemy(player))
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);
}
return(0);
}