/*
* undead.c
* Functions for undead players.
* ____ _
* | _ \ ___ __ _| |_ __ ___ ___
* | |_) / _ \/ _` | | '_ ` _ \/ __|
* | _ < __/ (_| | | | | | | \__ \
* |_| \_\___|\__,_|_|_| |_| |_|___/
*
* 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"
//*********************************************************************
// cmdBite
//*********************************************************************
int cmdBite(Player* player, cmd* cmnd) {
Creature* target=0;
Player *pTarget=0;
long i=0, t=0;
int chance=0, m=0, dmgnum=0;
Damage damage;
if(!player->ableToDoCommand() || !player->checkAttackTimer())
return(0);
if(cmnd->num < 2) {
player->print("Bite whom?\n");
return(0);
}
if((!player->knowsSkill("bite") || !player->isEffected("vampirism")) && !player->isStaff()) {
player->print("You lack the fangs!\n");
return(0);
}
if(isDay() && !player->isCt()) {
player->print("You may only bite people during the night.\n");
return(0);
}
if(player->inCombat() && !player->checkStaff("Not while you're in combat.\n"))
return(0);
target = player->getRoom()->findCreature(player, cmnd->str[1], cmnd->val[1], true, true);
pTarget = target->getPlayer();
if(!target || target == player || (pTarget && strlen(cmnd->str[1]) < 3)) {
player->print("They aren't here.\n");
return(0);
}
if(!player->canAttack(target))
return(0);
if(player->isBlind()) {
player->printColor("^CYou're blind!\n");
return(0);
}
if(target->isEffected("drain-shield") && target->isMonster()) {
player->print("Your bite would be ineffective.\n");
return(0);
}
if( target->isUndead() &&
!player->checkStaff("That wont work on the undead.\n")
) {
if(target->isMonster())
target->getMonster()->addEnmCrt(player);
return(0);
}
i = player->lasttime[LT_PLAYER_BITE].ltime;
t = time(0);
if((t - i < 30L) && !player->isDm()) {
player->pleaseWait(30L-t+i);
return(0);
}
player->smashInvis();
player->setFishing(false);
if(pTarget) {
} else {
target->getMonster()->addEnmCrt(player);
// Activates lag protection.
if(player->flagIsSet(P_LAG_PROTECTION_SET))
player->setFlag(P_LAG_PROTECTION_ACTIVE);
}
player->updateAttackTimer(true, DEFAULT_WEAPON_DELAY);
player->lasttime[LT_PLAYER_BITE].ltime = t;
player->lasttime[LT_READ_SCROLL].interval = 3L;
player->lasttime[LT_READ_SCROLL].ltime = t;
player->lasttime[LT_PLAYER_BITE].interval = 30L;
chance = 35 + ((int)((player->getSkillLevel("bite") - target->getLevel()) * 20) + bonus((int) player->strength.getCur()) * 5);
chance = MIN(chance, 85);
if(target->isEffected("drain-shield"))
chance /= 2;
if(player->isDm())
chance = 100;
if(mrand(1, 100) > chance) {
player->print("%s eludes your bite.\n", target->upHeShe());
player->checkImprove("bite", false);
target->print("%M tried to bite you!\n",player);
broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M tried to bite %N.", player, target);
return(0);
}
damage.set(mrand((int)(player->getSkillLevel("bite")*3), (int)(player->getSkillLevel("bite")*4)));
target->modifyDamage(player, NEGATIVE_ENERGY, damage);
dmgnum = damage.get();
m = MIN(target->hp.getCur(), damage.get());
damage.set(MIN(damage.get(), target->hp.getCur() + 1));
if(damage.get() < 1)
damage.set(1);
if(target->isMonster())
target->getMonster()->addEnmDmg(player, m);
player->printColor("You bite %N for %s%d^x damage.\n", target, player->customColorize("*CC:DAMAGE*"), dmgnum);
player->checkImprove("bite", true);
if(player->hp.getCur() < player->hp.getMax() && damage.getDrain()) {
player->print("The blood of %N revitalizes your strength.\n", target);
player->hp.increase(damage.getDrain());
}
if(player->getClass() == CARETAKER)
log_immort(false,player, "%s bites %s.\n", player->name, target->name);
target->printColor("%M bites you for %s%d^x damage.\n", player, target->customColorize("*CC:DAMAGE*"), dmgnum);
target->stun((mrand(5, 8) + bonus((int) player->strength.getCur())));
broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M bites %N!", player, target);
broadcastGroup(false, target, "^M%M^x bites ^M%N^x for *CC:DAMAGE*%d^x damage, %s%s\n",
player, target, dmgnum, target->heShe(), target->getStatusStr(dmgnum));
player->statistics.attackDamage(dmgnum, "bite");
if(player->doDamage(target, damage.get(), CHECK_DIE)) {
if(player->getClass() == CARETAKER)
log_immort(true, player, "%s killed %s with a bite.\n", player->name, target->name);
} else {
if(!induel(player, pTarget)) {
// 5% chance to get porphyria when bitten by a vampire
target->addPorphyria(player, 5);
}
}
return(0);
}
//*********************************************************************
// `Mist
//*********************************************************************
int cmdMist(Player* player, cmd* cmnd) {
ctag *cp=0;
long i=0, t=0;
int has_group=0;
t = time(0);
i = player->getLTAttack() > LT(player, LT_SPELL) ? player->getLTAttack() : LT(player, LT_SPELL);
if(LT(player, LT_MIST) > i)
i = LT(player, LT_MIST);
if(!player->ableToDoCommand())
return(0);
if((!player->knowsSkill("mist") || !player->isEffected("vampirism")) && !player->isStaff()) {
player->print("You are unable to turn to mist.\n");
return(0);
}
if(player->getRoom()->flagIsSet(R_ETHEREAL_PLANE)) {
player->print("That is not possible here.\n");
return(0);
}
if(t < i) {
player->pleaseWait(i-t);
return(0);
}
if(isDay() && !player->isCt()) {
player->print("You may only turn to mist during the night.\n");
return(0);
}
if(player->flagIsSet(P_OUTLAW)) {
player->print("You are unable to mist right now.\n");
return(0);
}
if(player->getRoom()->flagIsSet(R_DISPERSE_MIST)) {
player->print("Swirling vapors prevent you from entering mist form.\n");
return(0);
}
cp = player->first_fol;
while(cp) {
if(cp->crt && !cp->crt->flagIsSet(P_DM_INVIS)) {
has_group = 1;
break;
}
cp = cp->next_tag;
}
if(player->following) {
player->print("You can't do that while following someone.\n");
return(0);
}
if(has_group) {
player->print("You can't do that when someone is following you.\n");
return(0);
}
if(player->flagIsSet(P_MISTED)) {
player->print("You are already a mist.\n");
return(0);
}
if(player->inCombat()) {
player->print("Not in the middle of combat.\n");
return(0);
}
broadcast(player->getSock(), player->getRoom(), "%M turns to mist.", player);
player->setFlag(P_MISTED);
player->print("You turn to mist.\n");
//player->checkImprove("mist", true);
player->clearFlag(P_SITTING);
player->setFishing(false);
player->lasttime[LT_MIST].ltime = time(0);
player->lasttime[LT_MIST].interval = 3L;
return(0);
}
//*********************************************************************
// cmdUnmist
//*********************************************************************
int cmdUnmist(Player* player, cmd* cmnd) {
if(player->flagIsSet(P_MISTED)) {
player->unmist();
} else {
if(!player->isEffected("vampirism") && !player->isStaff())
return(0);
player->print("You are not in mist form.\n");
}
return(0);
}
//*********************************************************************
// cmdHypnotize
//*********************************************************************
int cmdHypnotize(Player* player, cmd* cmnd) {
Creature* target=0;
int dur=0, chance=0;
long i=0, t=0;
player->clearFlag(P_AFK);
if(!player->ableToDoCommand())
return(0);
if(!player->knowsSkill("hypnotize")) {
player->print("You lack the training to hypnotize anyone!\n");
return(0);
}
if(!player->isEffected("vampirism") && !player->isStaff()) {
player->print("Only vampires may hypnotize people.\n");
return(0);
}
if(cmnd->num < 2) {
player->print("Hypnotize whom?\n");
return(0);
}
i = LT(player, LT_HYPNOTIZE);
t = time(0);
if(i > t && !player->isDm()) {
player->pleaseWait(i-t);
return(0);
}
dur = 300 + mrand(1, 30) * 10 + bonus((int) player->constitution.getCur()) * 30 +
(int)(player->getSkillLevel("hypnotize") * 5);
cmnd->str[1][0] = up(cmnd->str[1][0]);
target = player->getRoom()->findCreature(player, cmnd->str[1], cmnd->val[1], false);
if(!target || target == player || (target->isPlayer() && strlen(cmnd->str[1]) < 3)) {
player->print("That's not here.\n");
return(0);
}
if(!target->canSee(player) && !player->checkStaff("Your victim must see you to be hypnotized.\n"))
return(0);
if(!player->canAttack(target))
return(0);
if(target->isMonster()) {
if(target->getMonster()->isEnmCrt(player->name)) {
player->print("Not while you are already fighting %s.\n", target->himHer());
return(0);
}
}
if( target->isPlayer() &&
( player->vampireCharmed(target->getPlayer()) ||
(target->hasCharm(player->name) && player->flagIsSet(P_CHARMED))
)
) {
player->print("But they are already your good friend!\n");
return(0);
}
if(target->isPlayer() && target->getClass() == RANGER && target->getLevel() > player->getLevel()) {
player->print("%M is immune to your hypnotizing gaze.\n", target);
return(0);
}
if(target->isMonster() && (target->flagIsSet(M_NO_CHARM) || (target->intelligence.getCur() < 3)) ) {
player->print("Your hypnotism fails.\n");
return(0);
}
if( target->isUndead() &&
!player->checkStaff("You cannot hypnotize undead beings.\n") )
return(0);
player->smashInvis();
player->lasttime[LT_HYPNOTIZE].ltime = t;
player->lasttime[LT_HYPNOTIZE].interval = 600L;
chance = MIN(90, 40 + (int)(player->getSkillLevel("hypnotize") - target->getLevel()) * 20 + 4 *
bonus((int) player->intelligence.getCur()));
if(target->flagIsSet(M_PERMENANT_MONSTER))
chance-=25;
if(player->isDm())
chance = 101;
if(mrand(1, 100) > chance && !player->isCt()) {
player->print("You fail to hypnotize %N.\n", target);
player->checkImprove("hypnotize", false);
broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M attempts to hypnotize %N.",player, target);
if(target->isMonster()) {
target->getMonster()->addEnmCrt(player);
if(player->flagIsSet(P_LAG_PROTECTION_SET)) { // Activates lag protection.
player->setFlag(P_LAG_PROTECTION_ACTIVE);
}
return(0);
}
target->printColor("^m%M tried to hypnotize you.\n", player);
return(0);
}
if((target->isPlayer() && target->isEffected("resist-magic")) ||
(target->isMonster() && target->isEffected("resist-magic")))
dur /= 2;
if(!player->isCt()) {
if(target->chkSave(MEN, player,0)) {
player->print("%M avoided your hypnotizing gaze.\n", target);
player->checkImprove("hypnotize", false);
target->print("You avoided %s's hypnotizing gaze.\n", player->name);
return(0);
}
}
log_immort(false,player, "%s hypnotizes %s.\n", player->name, target->name);
player->print("You hypnotize %N.\n", target);
player->checkImprove("hypnotize", true);
broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M hypnotizes %N!", player, target);
target->print("%M hypnotizes you.\n", player);
player->addCharm(target);
target->lasttime[LT_CHARMED].ltime = time(0);
target->lasttime[LT_CHARMED].interval = dur;
if(target->isPlayer())
target->setFlag(P_CHARMED);
else
target->setFlag(M_CHARMED);
return(0);
}
//*********************************************************************
// cmdRegenerate
//*********************************************************************
// This command is for liches.
int cmdRegenerate(Player* player, cmd* cmnd) {
int chance=0, xtra=0, pasthalf=0;
long i=0, t=0;
ctag *cp=0;
if(!player->ableToDoCommand())
return(0);
player->clearFlag(P_AFK);
if(!player->knowsSkill("regenerate")) {
player->print("You lack the training to regenerate.\n");
return(0);
}
if(player->inCombat() &&
!player->checkStaff("You are too busy to draw from the life energy around you.\n"))
return(0);
if(!player->isCt()) {
if(player->hp.getCur() > player->hp.getMax() * 3 / 4) {
player->printColor("^cYou cannot regenerate when past 3/4 of your life force.\n");
return(0);
}
i = player->lasttime[LT_REGENERATE].ltime + player->lasttime[LT_REGENERATE].interval;
t = time(0);
if(i > t) {
player->pleaseWait(i-t);
return(0);
}
}
if( player->getAlignment() > 100 &&
!player->checkStaff("There isn't enough evil in your soul to regenerate.\n")
)
return(0);
int level = (int)player->getSkillLevel("regenerate");
// get a base number:
// 10 = -36.66
// 120 = 0
// 400 = 93.3
chance = (player->constitution.getCur() - 120) / 3;
chance = MIN(85, level * 4 + chance);
if(player->isCt())
chance = 101;
if(mrand(1, 100) <= chance) {
player->print("You feel the evil in your soul rebuilding.\n");
player->checkImprove("regenerate", true);
broadcast(player->getSock(), player->getRoom(), "%M regenerates.", player);
cp = player->getRoom()->first_ply;
while(cp) {
if(!player->isUndead())
cp->crt->print("You shiver from a sudden deathly coldness.\n");
cp = cp->next_tag;
}
player->hp.increase(mrand(level+4,level*(5/2)+5));
// Prevents players from avoiding the 75% hp limit to allow regenerate
// by casting on themselves to get below half. A lich may never regenerate
// past 75% their max HP. This totally evens out their ticktime with mages
if(player->hp.getCur() > player->hp.getMax() * 3 / 4) {
player->hp.setCur((player->hp.getMax() * 3 / 4) + 1);
pasthalf = 1;
}
// Extra regeneration from being extremely evil.
if(player->getAlignment() <= -250 && !pasthalf) {
if(player->getAlignment() <= -400)
xtra = mrand(8,10);
else
xtra = mrand(4,6);
player->print("Your life force regenerates %d more due to your extreme evil.\n",xtra);
player->hp.increase(xtra);
}
player->lasttime[LT_REGENERATE].ltime = t;
player->lasttime[LT_REGENERATE].interval = 120L;
} else {
player->print("You fail to regenerate.\n");
player->checkImprove("regenerate", false);
broadcast(player->getSock(), player->getRoom(), "%M tried to regenerate.", player);
player->lasttime[LT_REGENERATE].ltime = t;
player->lasttime[LT_REGENERATE].interval = 10L;
}
return(0);
}
//*********************************************************************
// cmdDrainLife
//*********************************************************************
// This allows a lich to drain hp from someone else and add half the
// damage to their own
int cmdDrainLife(Player* player, cmd* cmnd) {
Creature* target=0;
Player *pTarget=0;
long i=0, t=0;
int chance=0;
Damage damage;
if(!player->ableToDoCommand())
return(0);
if(cmnd->num < 2) {
player->print("Drain whom?\n");
return(0);
}
if(!player->knowsSkill("drain")) {
player->print("You haven't learned how to drain someone's life.\n");
return(0);
}
if(player->inCombat()) {
player->print("Not while you're already in combat.\n");
return(0);
}
target = player->getRoom()->findCreature(player, cmnd->str[1], cmnd->val[1], true, true);
pTarget = target->getPlayer();
if(!target || target == player || (pTarget && strlen(cmnd->str[1]) < 3)) {
player->print("You don't see that here.\n");
return(0);
}
player->smashInvis();
player->setFishing(false);
if(!player->canAttack(target))
return(0);
if( target->isUndead() &&
!player->checkStaff("You may only drain the life of the living.\n") )
return(0);
if(!pTarget) {
// Activates lag protection.
if(player->flagIsSet(P_LAG_PROTECTION_SET))
player->setFlag(P_LAG_PROTECTION_ACTIVE);
if(target->isPet()) {
if(!player->flagIsSet(P_CHAOTIC) && !player->isCt() && !target->following->flagIsSet(P_OUTLAW)) {
player->print("Sorry, you're lawful.\n");
return(0);
}
if(!target->following->flagIsSet(P_CHAOTIC) && !player->isCt() && !target->following->flagIsSet(P_OUTLAW)) {
player->print("Sorry, that creature is lawful.\n");
return(0);
}
if(player->getRoom()->flagIsSet(R_SAFE_ROOM) && !target->following->flagIsSet(P_OUTLAW)) {
player->print("No killing allowed in this room.\n");
return(0);
}
}
}
i = LT(player, LT_DRAIN_LIFE);
t = time(0);
if(i > t && !player->isDm()) {
player->pleaseWait(i-t);
return(0);
}
if(target->isMonster())
target->getMonster()->addEnmCrt(player);
player->lasttime[LT_DRAIN_LIFE].ltime = t;
player->updateAttackTimer(true, DEFAULT_WEAPON_DELAY);
player->lasttime[LT_DRAIN_LIFE].interval = 120L;
int level = (int)player->getSkillLevel("drain");
chance = (level - target->getLevel()) * 20 + bonus((int) player->constitution.getCur()) * 5 + 25;
chance = MIN(chance, 80);
if(target->isEffected("drain-shield"))
chance /= 2;
if(mrand(1, 100) > chance) {
player->print("You failed to drain %N's life.\n", target);
player->checkImprove("drain", false);
broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M tried to drain %N's life.", player, target);
target->print("%M tried drain your life!\n", player);
return(0);
}
damage.set(mrand(level * 2, level * 4));
if(target->isEffected("drain-shield"))
damage.set(mrand(1, level));
// Berserked barbarians have more energy to drain
if(pTarget && pTarget->flagIsSet(P_BERSERKED))
damage.set(damage.get() + (damage.get() / 5));
damage.set(MIN(damage.get(), target->hp.getCur() + 1));
if(damage.get() < 1)
damage.set(1);
if(!target->isCt()) {
if(target->chkSave(DEA, player, 0)) {
player->printColor("^yYour life-drain failed!\n");
target->print("%M failed to drain your life.\n", player);
return(0);
}
}
target->modifyDamage(player, NEGATIVE_ENERGY, damage);
// drain heals us
if(!target->isEffected("drain-shield"))
player->hp.increase(damage.get() / 2);
if(target->isMonster())
target->getMonster()->addEnmDmg(player, damage.get());
player->printColor("You drained %N for %s%d^x damage.\n", target, player->customColorize("*CC:DAMAGE*"), damage.get());
player->checkImprove("drain", true);
player->statistics.attackDamage(damage.get(), "drain-life");
if(target->isEffected("drain-shield"))
player->print("%M resisted your drain!\n", target);
target->printColor("%M drained you for %s%d^x damage.\n", player, target->customColorize("*CC:DAMAGE*"), damage.get());
broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M drained %N's life.", player, target);
if(player->doDamage(target, damage.get(), CHECK_DIE)) {
if(player->getClass() == CARETAKER && pTarget)
log_immort(true, player, "%s killed %s with the drain.\n", player->name, target->name);
}
return(0);
}