/*
* healmagic.cpp
* Healing magic routines.
* ____ _
* | _ \ ___ __ _| |_ __ ___ ___
* | |_) / _ \/ _` | | '_ ` _ \/ __|
* | _ < __/ (_| | | | | | | \__ \
* |_| \_\___|\__,_|_|_| |_| |_|___/
*
* 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 "magic.h"
#include "effects.h"
#include "move.h"
//*********************************************************************
// healCombatCheck
//*********************************************************************
bool healCombatCheck(Creature* healer, Creature* target, bool print=true) {
Monster* mTarget = target->getMonster();
if(!mTarget)
return(true);
if(mTarget->isPet() && mTarget->following == healer)
return(true);
if(!mTarget->getMonster()->nearEnemy())
return(true);
if(target->getMonster()->isEnmCrt(healer->name))
return(true);
// if healer is in group with pet, they can heal
ctag* cp = (healer->following ? healer->following : healer)->first_fol;
while(cp) {
if(cp->crt == healer)
return(true);
cp = cp->next_tag;
}
if(print)
healer->print("Not while %N is in combat with someone.\n", target);
return(false);
}
//*********************************************************************
// getHeal
//*********************************************************************
int getHeal(Creature *healer, Creature* target, int spell) {
Player *pHealer = healer->getPlayer();
int level=0, statBns=0, base=0, mod=0, heal=0, dmg=0;
int vigPet=0;
ctag *cp=0;
if(target) {
/* Mobs with intelligence > 12 do not like people vigging their enemies and
will attack them. -TC */
if(target != healer && target->isPlayer() && target->inCombat()) {
cp = target->getRoom()->first_mon;
while(cp) {
if(cp->crt->intelligence.getCur() > 120 && cp->crt->getMonster()->isEnmCrt(target->name))
cp->crt->getMonster()->addEnmCrt(healer);
cp = cp->next_tag;
}
}
if(target == healer)
target = 0;
}
level = healer->getLevel();
if(pHealer && pHealer->getClass() == CLERIC &&
(pHealer->getSecondClass() == FIGHTER || pHealer->getSecondClass() == ASSASSIN) )
level /= 2;
if(target)
vigPet = target->isPet() && target->following == healer;
switch(spell) {
case S_VIGOR:
base = mrand(1,8); //1d8
break;
case S_MEND_WOUNDS:
base = dice(2,7,0); //2d7
break;
case S_REJUVENATE:
base = dice(1,6,1); // 1d6+1
break;
}
switch(healer->getClass()) {
case CLERIC:
statBns = bonus((int)healer->piety.getCur());
switch(healer->getDeity()) {
case CERIS:
if(healer->getAdjustedAlignment() == BLOODRED || healer->getAdjustedAlignment() == ROYALBLUE) {
healer->print("Your healing is not as effective while so far out of natural balance.\n");
level /= 2;
}
mod = level / 2 + mrand(1, 1 + level / 2);
if(healer->getAdjustedAlignment() == NEUTRAL) {
if(spell != S_REJUVENATE)
healer->print("Your harmonial balance gains you power with Ceris.\n");
mod += mrand(1,4);
}
if(spell == S_MEND_WOUNDS)
mod += level / 2;
if(spell == S_REJUVENATE)
mod = level / 3 + mrand(1, 1 + level / 3);
break;
case ARES:
level /= 2; // Ares clerics vig as if 1/2 their level
if(healer->getAdjustedAlignment() >= BLUISH || healer->getAdjustedAlignment() <= REDDISH) {
healer->print("Your soul is too far out of balance.\n");
level /= 2;
}
mod = level / 2 + mrand(1, 1 + level / 2);
if(spell == S_MEND_WOUNDS)
mod += level / 2;
break;
case KAMIRA:
level = (level*3)/4;
if(healer->getAdjustedAlignment() < PINKISH) {
healer->print("Being evil at heart is distorting your healing magic.\n");
level /= 2;
}
mod = level / 2 + mrand(1, 1 + level / 2);
if(spell == S_MEND_WOUNDS)
mod += level / 2;
break;
case JAKAR:
if(healer->getAdjustedAlignment() != NEUTRAL) {
healer->print("Your soul is out of balance.\n");
level /= 2;
}
mod = level / 2 + mrand(1, 1 + level / 2);
if(spell == S_MEND_WOUNDS)
mod += level / 2;
mod = (mod*3)/4;
break;
}// end deity switch
break;
case DRUID:
statBns = MAX(bonus((int)healer->intelligence.getCur()), bonus((int)healer->constitution.getCur()));
mod = level/4 + mrand(1, 1 + level / 5);
break;
case THIEF:
case ASSASSIN:
case ROGUE:
case FIGHTER:
case BERSERKER:
case WEREWOLF:
statBns = bonus((int)healer->constitution.getCur());
mod = 0;
break;
case MONK:
statBns = bonus((int)healer->constitution.getCur());
mod = mrand(1,6);
break;
case RANGER:
case BARD:
case VAMPIRE:
statBns = MAX(bonus((int)healer->piety.getCur()), bonus((int)healer->intelligence.getCur()));
mod = mrand(1,6);
break;
case MAGE:
statBns = MAX(bonus((int)healer->piety.getCur()), bonus((int)healer->intelligence.getCur()));
mod = 0;
break;
case CARETAKER:
case DUNGEONMASTER:
statBns = MAX(bonus((int)healer->piety.getCur()), bonus((int)healer->intelligence.getCur()));
mod = mrand(level/2, level);
break;
default:
statBns = 0;
mod = 0;
break;
} // end class switch
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// clerics and paladins of Gradius
if(healer->getDeity() == GRADIUS) {
statBns = bonus((int)healer->piety.getCur());
if(pHealer && !pHealer->alignInOrder()) {
healer->print("You are out of balance with the earth. Your healing is weakened.\n");
level /= 2;
}
if(target && target->isAntiGradius()) {
healer->print("%s is very puzzled by your healing beings of vile races.\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
mod /= 2;
}
if(healer->getClass() == CLERIC) {
mod = level / 2 + mrand(1, 1 + level / 2);
if(spell == S_MEND_WOUNDS)
mod += level / 2;
mod = (mod*3)/4;
} else {
if(spell == S_VIGOR)
mod = level / 3 + mrand(1, 1 + level / 4);
else
mod = level / 2 + mrand(1, 1 + level / 3);
}
// clerics and paladins of Enoch and Linothan
} else if(healer->getDeity() == ENOCH || healer->getDeity() == LINOTHAN) {
statBns = bonus((int)healer->piety.getCur());
if(pHealer && !pHealer->alignInOrder()) {
healer->print("Your healing magic is weakened from lack of faith in %s.\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
level /= 2;
}
if(target && target->getAdjustedAlignment() < NEUTRAL && healer != target) {
healer->print("It concerns %s that you heal the unrighteous and impure of heart.\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
healer->subAlignment(1);
mod /= 2;
}
if(healer->getClass() == CLERIC) {
mod = level / 2 + mrand(1, 1 + level / 2);
if(spell == S_MEND_WOUNDS)
mod += level / 2;
} else {
if(spell == S_VIGOR)
mod = level / 3 + mrand(1, 1 + level / 4);
else
mod = level / 2 + mrand(1, 1 + level / 3);
}
// clerics and deathknights of Aramon and Arachnus
} else if(healer->getDeity() == ARAMON || healer->getDeity() == ARACHNUS) {
statBns = bonus((int)healer->piety.getCur());
if(pHealer && !pHealer->alignInOrder())
level /= 2;
if(healer->getAdjustedAlignment() >= LIGHTBLUE) {
healer->print("FOOL! You dare turn from %s's evil ways!\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
dmg = mrand(1,10);
healer->print("You are shocked for %d damage by %s's wrath!\n", dmg, gConfig->getDeity(healer->getDeity())->getName().c_str());
broadcast(healer->getSock(), healer->getRoom(), "%M doubles over in pain and wretches.\n", healer);
healer->hp.decrease(dmg);
mod = 0;
} else if(target && healer != target && !vigPet) {
if(target->getAdjustedAlignment() > LIGHTBLUE) {
healer->print("How DARE you heal the righteous and good of heart!\n");
dmg = mrand(1,10);
healer->print("You are shocked for %d damage by %s's wrath!\n", dmg, gConfig->getDeity(healer->getDeity())->getName().c_str());
broadcast(healer->getSock(), healer->getRoom(), "%M doubles over in pain and wretches.\n", healer);
healer->hp.decrease(dmg);
mod = 0;
} else if( healer->getDeity() == ARAMON || (
healer->getDeity() == ARACHNUS &&
(healer->willIgnoreIllusion() ? target->getRace() : target->getDisplayRace()) != DARKELF
)) {
if(healer->getDeity() == ARAMON)
healer->print("%s disapproves of healing others than yourself.\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
else
healer->print("%s disapproves of healing non-dark-elves.\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
mod = mrand(1, (1 + level / 5));
}
} else {
if(healer->getClass() == CLERIC) {
mod = level / 2 + mrand(1, 1 + level / 2);
if(spell == S_MEND_WOUNDS)
mod += level / 2;
} else {
mod = level / 4 + mrand(1, 1 + level / 4);
}
}
}
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
heal = base + statBns + mod;
if(healer->getRoom()->magicBonus()) {
if(spell == S_MEND_WOUNDS)
heal += mrand(1, 6);
else
heal += mrand(1, 3);
healer->print("The room's magical properties increase the power of your spell.\n");
}
if(target && healer != target) {
if(target->isPlayer()) {
if(target->isEffected("stoneskin"))
heal /= 2;
if(target->flagIsSet(P_POISONED_BY_PLAYER))
heal = mrand(1,4);
if(target->flagIsSet(P_OUTLAW) && target->getRoom()->flagIsSet(R_OUTLAW_SAFE))
heal = mrand(1,3);
}
} else {
if(healer->isEffected("stoneskin"))
heal /= 2;
if(healer->flagIsSet(P_OUTLAW) && healer->getRoom()->flagIsSet(R_OUTLAW_SAFE))
heal = mrand (1,3);
}
return(MAX(1, heal));
}
void niceExp(Creature *healer, Creature *creature, int heal, int how) {
Player *player=0, *target=0;
int exp=0;
if(how != CAST)
return;
// only players are allowed to use this function! It's called from creature-spells
// though, so we have to cast
player = healer->getPlayer();
target = creature->getPlayer();
if(!player || !target || healer == target)
return;
if(player->getDeity() == CERIS || player->getDeity() == ENOCH || player->getDeity() == LINOTHAN)
exp = MAX(1, heal) / 4;
else
exp = MAX(1, heal) / 3;
if(player->getDeity() == ARAMON)
exp = 0;
// also see getHeal for copy of this
if( player->getDeity() == ARACHNUS && (
target->getAdjustedAlignment() > LIGHTBLUE ||
(player->willIgnoreIllusion() ? target->getRace() : target->getDisplayRace()) != DARKELF)
)
exp = 0;
if(exp && (target->hp.getCur() < target->hp.getMax())) {
if(player->halftolevel())
exp = 0;
player->addExperience(exp);
healer->print("You %s %d experience for your deed.\n", gConfig->isAprilFools() ? "lose" : "gain", exp);
player->checkLevel();
}
}
//*********************************************************************
// canCastHealing
//*********************************************************************
bool canCastHealing(Creature* player, Creature* target, bool rej=false, bool healSpell=false, bool print=true) {
if(!healCombatCheck(player, target, print))
return(false);
if(target->isEffected("petrification")) {
if(print)
player->print("Your %s magic is ineffective.\n", rej ? "healing" : "rejuvinating");
return(false);
}
// for a lich, a heal spell is offensive magic
if(target->getClass() == LICH && healSpell)
return(true);
if(target->getClass() == LICH) {
if(print)
player->print("The aura of death around %N nullifies your %s magic.\n", target, rej ? "healing" : "rejuvinating");
return(false);
}
if(!rej && target->isEffected("stoneskin")) {
// don't check this for liches
if(print)
player->print("%M's stoneskin spell reflects your %s magic.\n", target, rej ? "healing" : "rejuvinating");
return(false);
}
if(checkRefusingMagic(player, target, true, print))
return(false);
if(!rej && target->hp.getCur() >= target->hp.getMax()) {
if(print)
player->print("%M is at full health right now.\n", target);
return(false);
}
return(true);
}
//*********************************************************************
// splVigor
//*********************************************************************
// This function will cause the vigor spell to be cast on a player or
// another monster.
int splVigor(Creature* player, cmd* cmnd, SpellData* spellData) {
Creature* target=0;
int heal=0;
if(player->getClass() == LICH) {
player->print("Your class prevents you from casting that spell.\n");
return(0);
}
// Vigor self
if(cmnd->num == 2) {
if( player->hp.getCur() >= player->hp.getMax() &&
!player->checkStaff("You are already at full health right now.\n") )
return(0);
if(spellData->how == CAST) {
if(player->isPlayer())
player->getPlayer()->statistics.healingCast();
heal = getHeal(player, 0, S_VIGOR);
} else
heal = mrand(1, 8);
player->hp.increase(heal);
if(spellData->how == CAST || spellData->how == SCROLL) {
player->print("Vigor spell cast.\n");
broadcast(player->getSock(), player->getRoom(), "%M casts a vigor spell on %sself.",
player, player->himHer());
return(1);
} else {
player->print("You feel better.\n");
return(1);
}
// Cast vigor on another player or monster
} else {
if(noPotion(player, spellData))
return(0);
cmnd->str[2][0] = up(cmnd->str[2][0]);
target = player->getRoom()->findCreature(player, cmnd->str[2], cmnd->val[2], false);
if(!target) {
player->print("That person is not here.\n");
return(0);
}
if(!canCastHealing(player, target))
return(0);
if(target->inCombat(false))
player->smashInvis();
if(spellData->how == CAST) {
if(player->isPlayer())
player->getPlayer()->statistics.healingCast();
heal = getHeal(player, target, S_VIGOR);
} else
heal = mrand(1, 8);
target->hp.increase(heal);
if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
player->print("Vigor spell cast on %N.\n", target);
target->print("%M casts a vigor spell on you.\n", player);
broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M casts a vigor spell on %N.",
player, target);
niceExp(player, target, heal, spellData->how);
return(1);
}
}
return(1);
}
//*********************************************************************
// splMendWounds
//*********************************************************************
// This function will cause the mend spell to be cast on a player or
// another monster. It heals 2d7 hit points plus any bonuses for
// intelligence. If the player is a cleric then there is an additional
// point of healing for each level of the cleric.
int splMendWounds(Creature* player, cmd* cmnd, SpellData* spellData) {
Creature* target=0;
int heal=0;
if(player->getClass() == LICH) {
player->print("Your class prevents you from casting that spell.\n");
return(0);
}
// Mend self
if(cmnd->num == 2) {
if( player->hp.getCur() >= player->hp.getMax() &&
!player->checkStaff("You are already at full health right now.\n") )
return(0);
if(spellData->how == CAST) {
if(player->isPlayer())
player->getPlayer()->statistics.healingCast();
heal = getHeal(player, 0, S_MEND_WOUNDS);
} else
heal = dice(2, 7, 0);
addhp(player, heal);
if(spellData->how == CAST || spellData->how == SCROLL) {
player->print("Mend-wounds spell cast.\n");
broadcast(player->getSock(), player->getRoom(), "%M casts a mend-wounds spell on %sself.",
player, player->himHer());
return(1);
} else {
player->print("You feel better.\n");
return(1);
}
// Cast mend on another player or monster
} else {
if(noPotion(player, spellData))
return(0);
cmnd->str[2][0] = up(cmnd->str[2][0]);
target = player->getRoom()->findCreature(player, cmnd->str[2], cmnd->val[2], false);
if(!target) {
player->print("That person is not here.\n");
return(0);
}
if(!healCombatCheck(player, target))
return(0);
if(target->inCombat(false))
player->smashInvis();
if(spellData->how == CAST) {
if(player->isPlayer())
player->getPlayer()->statistics.healingCast();
heal = getHeal(player, target, S_MEND_WOUNDS);
} else
heal = dice(2, 8, 0);
addhp(target, heal);
if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
player->print("Mend-wounds spell cast on %N.\n", target);
target->print("%M casts a mend-wounds spell on you.\n", player);
broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M casts a mend-wounds spell on %N.",
player, target);
niceExp(player, target, heal, spellData->how);
return(1);
}
}
return(1);
}
//*********************************************************************
// splRejuvenate
//*********************************************************************
// This function will cause the vigor spell to be cast on a player or
// another monster.
int splRejuvenate(Creature* player, cmd* cmnd, SpellData* spellData) {
Creature* target=0;
int heal=0, mpHeal=0;
if(!(player->getClass() == CLERIC && player->getDeity() == CERIS) && spellData->how == CAST && !player->isCt()) {
player->print("%s does not grant you the power to cast that spell.\n", gConfig->getDeity(player->getDeity())->getName().c_str());
return(0);
}
if(player->getLevel() < 13 && !player->isCt()) {
player->print("You are not high enough in your order to cast that spell.\n");
return(0);
}
if(player->mp.getCur() < 8 && spellData->how == CAST) {
player->print("Not enough magic points.\n");
return(0);
}
if(player->flagIsSet(P_NO_TICK_MP)) {
player->print("You cannot cast that spell right now.\n");
return(0);
}
// Rejuvenate self
if(cmnd->num == 2) {
if( player->hp.getCur() >= player->hp.getMax() &&
player->mp.getCur() >= player->mp.getMax() &&
!player->checkStaff("You are already at full health and magic right now.\n") )
return(0);
if(spellData->how == CAST) {
if(player->isPlayer())
player->getPlayer()->statistics.healingCast();
heal = getHeal(player, 0, S_REJUVENATE);
mpHeal = getHeal(player, 0, S_REJUVENATE);
if(!player->isCt()) {
player->lasttime[LT_SPELL].ltime = time(0);
player->lasttime[LT_SPELL].interval = 24L;
}
player->mp.decrease(8);
} else {
heal = mrand(1,8);
mpHeal = mrand(1,8);
}
addhp(player, heal);
addmp(player, mpHeal);
if(spellData->how == CAST || spellData->how == SCROLL) {
player->print("Rejuvenate spell cast.\n");
broadcast(player->getSock(), player->getRoom(), "%M casts a rejuvenate spell on %sself.",
player, player->himHer());
} else {
player->print("You feel revitalized.\n");
}
// Cast rejuvenate on another player or monster
} else {
if(noPotion(player, spellData))
return(0);
cmnd->str[2][0] = up(cmnd->str[2][0]);
target = player->getRoom()->findCreature(player, cmnd->str[2], cmnd->val[2], false);
if(!target) {
player->print("That person is not here.\n");
return(0);
}
if(!canCastHealing(player, target, true))
return(0);
if(target->hp.getCur() >= target->hp.getMax() && target->mp.getCur() >= target->mp.getMax()) {
player->print("%M is at full health and magic right now.\n", target);
return(0);
}
if(target->flagIsSet(P_NO_TICK_MP) || target->flagIsSet(P_NO_TICK_HP)) {
player->print("Your rejuvinating magic is ineffective.\n");
return(0);
}
if(target->inCombat(false))
player->smashInvis();
if(spellData->how == CAST && !player->isCt()) {
player->lasttime[LT_SPELL].ltime = time(0);
player->lasttime[LT_SPELL].interval = 24L;
}
if(spellData->how == CAST) {
if(player->isPlayer())
player->getPlayer()->statistics.healingCast();
player->mp.decrease(8);
heal = getHeal(player, target, S_REJUVENATE);
mpHeal = getHeal(player, target, S_REJUVENATE);
} else {
heal = mrand(1,8);
mpHeal = mrand(1,8);
}
addhp(target, heal);
addmp(target, mpHeal);
if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
player->print("Rejuvenate spell cast on %N.\n", target);
target->print("%M casts a rejuvenate spell on you.\n", player);
broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M casts a rejuvenate spell on %N.",
player, target);
niceExp(player, target, (heal+mpHeal)/2, spellData->how);
}
}
return(1);
}
//*********************************************************************
// splHeal
//*********************************************************************
// This function will cause the heal spell to be cast on a player or
// another monster. It heals all hit points damage but only works 3
// times a day.
int splHeal(Creature* player, cmd* cmnd, SpellData* spellData) {
Creature* creature=0;
if(spellData->how == CAST && !player->isStaff()) {
if(player->getClass() != CLERIC && player->getClass() != PALADIN && !player->isCt()) {
player->print("Your class prohibits you from casting that spell.\n");
return(0);
}
switch(player->getDeity()) {
case ARACHNUS:
case JAKAR:
case GRADIUS:
case ARES:
case ARAMON:
case KAMIRA:
player->print("%s does not allow you to cast that spell.\n", gConfig->getDeity(player->getDeity())->getName().c_str());
return(0);
default:
break;
}
}
// Heal self
if(cmnd->num == 2) {
if(!dec_daily(&player->daily[DL_FHEAL]) && spellData->how == CAST && !player->isCt() && player->isPlayer()) {
player->print("You have been granted that spell enough today.\n");
return(0);
}
//addhp(player, player->hp.getMax());
player->hp.restore();
if(spellData->how == CAST || spellData->how == SCROLL) {
if(player->isPlayer())
player->getPlayer()->statistics.healingCast();
player->print("Heal spell cast.\n");
broadcast(player->getSock(), player->getRoom(), "%M casts a heal spell on %sself.", player,
player->himHer());
return(1);
} else {
player->print("You feel incredibly better.\n");
return(1);
}
// Cast heal on another player or monster
} else {
if(noPotion(player, spellData))
return(0);
creature = player->getRoom()->findCreature(player, cmnd->str[2], cmnd->val[2], false);
if(!creature) {
player->print("That person is not here.\n");
return(0);
}
if(!dec_daily(&player->daily[DL_FHEAL]) && spellData->how == CAST &&
!player->isCt() && player->isPlayer()) {
player->print("You have been granted that spell enough times for today.\n");
return(0);
}
if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
if(!canCastHealing(player, creature, false, true))
return(0);
// addhp(creature, creature->hp.getMax());
if(creature->isPlayer() && creature->getClass() == LICH) {
if(!player->canAttack(creature))
return(0);
if(player->getRoom()->flagIsSet(R_SAFE_ROOM) && !creature->flagIsSet(P_OUTLAW)) {
player->print("Your heal spell will harm a lich.\n");
player->print("No killing is allowed here.\n");
return(0);
}
if(creature->isEffected("resist-magic")) {
player->print("Your spell fizzles.\n");
if(spellData->how == CAST)
player->subMp(20);
return(0);
}
} else if(creature->isMonster() && creature->getClass() == LICH) {
if(creature->isEffected("resist-magic")) {
player->print("Your spell fizzles.\n");
if(spellData->how == CAST)
player->subMp(20);
return(0);
}
}
if(creature->getClass() == LICH) {
if(creature->hp.getCur() >= 4)
creature->hp.setCur(mrand(2,4));
else
creature->hp.setCur(1);
player->print("The heal spell nearly kills %N!\n",creature);
if(creature->isPlayer())
creature->print("%M's heal spell sucks away your life force!\n", player);
broadcast(player->getSock(), creature->getSock(), player->getRoom(), "%M's heal spell nearly kills %N!",
player, creature);
player->smashInvis();
if(creature->isMonster())
creature->getMonster()->addEnmCrt(player);
return(1);
}
if(creature->inCombat(false))
player->smashInvis();
if(player->isPlayer())
player->getPlayer()->statistics.healingCast();
creature->hp.setCur(MAX(1, creature->hp.getMax() - mrand(1,4)));
player->print("Heal spell cast on %N.\n", creature);
creature->print("%M casts a heal spell on you.\n", player);
broadcast(player->getSock(), creature->getSock(), player->getRoom(), "%M casts a heal spell on %N.",
player, creature);
logCast(player, creature, "heal");
return(1);
}
}
return(1);
}
//*********************************************************************
// removeStatEffects
//*********************************************************************
void Creature::removeStatEffects() {
Player* pThis = getPlayer();
if(pThis) {
pThis->loseRage();
pThis->loseFrenzy();
pThis->losePray();
}
removeEffect("strength");
removeEffect("enfeeblement");
removeEffect("haste");
removeEffect("slow");
removeEffect("fortitude");
removeEffect("weakness");
removeEffect("insight");
removeEffect("feeblemind");
removeEffect("prayer");
removeEffect("damnation");
}
//*********************************************************************
// doRessLoss
//*********************************************************************
int doRessLoss(int curr, int prev, bool full) {
return(MAX(0, (prev - (full ? 0 : (prev - curr) / 5))));
}
//*********************************************************************
// doRess
//*********************************************************************
int doRess(Creature* caster, cmd* cmnd, bool ress) {
// if ress=false, it's a bloodfusion
Player *player = caster->getPlayer();
int a=0, prevLevel=0;
bool full=false;
long t=0;
Player* playerBackup=0, *target=0;
BaseRoom *newRoom=0;
char filename[80];
strcpy(filename, "");
if(player && !player->isDm()) {
if(player->getNegativeLevels()) {
player->print("You cannot do that without your full life essence.\n");
return(0);
}
if(player->mp.getCur() < player->mp.getMax()) {
player->print("You must have full MP to cast that spell.\n");
return(0);
}
} else {
// a DM can set to a 100% restore instead of 80%
if(cmnd->num==4 && !strcasecmp(cmnd->str[3], "-full"))
full = true;
}
if(cmnd->num < 2) {
caster->print("%s?\n", ress ? "Resurrect whom" : "Fuse whom with new blood");
return(0);
}
cmnd->str[2][0]=up(cmnd->str[2][0]);
target = gServer->findPlayer(cmnd->str[2]);
if(!target) {
caster->print("That player is not online.\n");
return(0);
}
if(target->isDm() && target->flagIsSet(P_DM_INVIS) && !caster->isDm()) {
caster->print("That player is not online.\n");
return(0);
}
if(target->isStaff()) {
caster->print("Staff characters do not need to be %s.\n",
ress ? "resurrected" : "fused with blood");
return(0);
}
if(checkRefusingMagic(caster, target))
return(0);
if(Move::tooFarAway(caster, target, ress ? "resurrect" : "fuse with new blood"))
return(0);
if(ress) {
if(target->isUndead()) {
caster->print("Undead players cannot be resurrected.\n");
return(0);
}
} else {
if(!target->isUndead()) {
caster->print("Only undead players can be fused with new blood.\n");
return(0);
}
}
if(!caster->isDm()) {
if(target->getLocation() != target->getLimboRoom()) {
caster->print("%s is not in limbo! How can you %s %s?\n",
target->name, ress ? "resurrect" : "bloodfuse", target->himHer());
return(0);
}
if(target->getLevel() < 7) {
caster->print("%s is not yet powerful enough to be %s.\n",
target->name, ress ? "resurrected" : "fused with blood");
return(0);
}
if(!target->flagIsSet(P_KILLED_BY_MOB)) {
caster->print("%s does not need to be %s.\n", target->name, ress ? "resurrected" : "fused with new blood");
return(0);
}
}
if(target == caster) {
caster->print("You cannot %s.\n", ress ? "resurrect yourself" : "fuse yourself with new blood");
return(0);
}
sprintf(filename, "%s/%s.bak.xml", BACKUPPATH, target->name);
if(!file_exists(filename)) {
caster->print("Error loading player backup!\n");
if(caster->isDm())
caster->print("File: %s\n", filename);
caster->print("Your %s attempt failed.\n", ress ? "resurrection" : "bloodfusion");
return(0);
}
if(player && !player->isDm() && !dec_daily(&player->daily[DL_RESURRECT])) {
player->print("You have done that enough times for today.\n");
return(0);
}
if(!caster->isDm() && !dec_daily(&target->daily[DL_RESURRECT])) {
caster->print("Players can only be %s once per 24 hours real time.\n", ress ? "resurrected" : "fused with new blood");
return(0);
}
caster->print("You cast a %s spell on %N.\n", ress ? "resurrection" : "bloodfusion", target);
prevLevel = target->getLevel();
// load the backed up player
if(!loadPlayer(target->name, &playerBackup, LS_BACKUP)) {
caster->print("File load failed.\n");
caster->print("Your %s attempt failed.\n", ress ? "resurrection" : "bloodfusion");
return(0);
}
if(target->getExperience() == playerBackup->getExperience()) {
caster->print("Target and backup have the same experience.\n");
caster->print("Your %s attempt failed.\n", ress ? "resurrection" : "bloodfusion");
free_crt(playerBackup, false);
return(0);
}
// Clear any stat-modifying effects from backed up player
//normalizeStats(playerBackup);
playerBackup->removeStatEffects();
if(!playerBackup->statsAddUp()) {
caster->print("Backup's stats do not add up.\n");
caster->print("Your %s attempt failed.\n", ress ? "resurrection" : "bloodfusion");
free_crt(playerBackup, false);
return(0);
}
target->removeStatEffects();
// set target's characteristics back to what they were before
target->setExperience(doRessLoss(target->getExperience(), playerBackup->getExperience(), full));
target->setLevel(playerBackup->getLevel());
target->setActualLevel(playerBackup->getActualLevel());
target->hp.setMax(playerBackup->hp.getMax());
target->mp.setMax(playerBackup->mp.getMax());
//target->pp.max = playerBackup->pp.max;
for(Realm r = MIN_REALM; r<MAX_REALM; r = (Realm)((int)r + 1)) {
target->setRealm(doRessLoss(target->getRealm(r), playerBackup->getRealm(r), full), r);
}
for(a=0; a<6; a++) {
// don't mess with saves
target->saves[a].chance = playerBackup->saves[a].chance;
target->saves[a].gained = playerBackup->saves[a].gained;
}
target->strength.setMax(playerBackup->strength.getMax());
target->strength.setCur(playerBackup->strength.getCur());
target->dexterity.setMax(playerBackup->dexterity.getMax());
target->dexterity.setCur(playerBackup->dexterity.getCur());
target->constitution.setMax(playerBackup->constitution.getMax());
target->constitution.setCur(playerBackup->constitution.getCur());
target->intelligence.setMax(playerBackup->intelligence.getMax());
target->intelligence.setCur(playerBackup->intelligence.getCur());
target->piety.setMax(playerBackup->piety.getMax());
target->piety.setCur(playerBackup->piety.getCur());
EffectInfo *effect = target->getEffect("death-sickness");
if(effect) {
if(full)
target->removeEffect("death-sickness");
else
effect->setDuration(effect->getDuration() / 3);
}
target->cureDisease();
target->curePoison();
target->removeEffect("hold-person");
target->removeEffect("petrification");
target->removeEffect("confusion");
target->removeEffect("drunkenness");
target->clearFlag(P_KILLED_BY_MOB);
target->setTickDamage(0);
// Free backed up player pointer from memory
free_crt(playerBackup, false);
broadcast(caster->getSock(), caster->getRoom(), "%M casts a %s spell on %N.", caster, ress ? "resurrection" : "bloodfusion", target);
logn("log.resurrect", "%s(L:%d) %s %s(L%d:%d) %s.\n", caster->name, caster->getLevel(),
ress ? "resurrected" : "fused", target->name, prevLevel, target->getLevel(),
ress ? "from the dead" : "with new blood");
if(ress)
broadcast("^R### %M just resurrected %s from the dead!", caster, target->name);
else
broadcast("^R### %M just fused %s with new blood!", caster, target->name);
if(player && !player->isDm()) {
t = time(0);
caster->setFlag(P_NO_TICK_MP);
// caster cannot tick MP for 20 mins online time
caster->lasttime[LT_NOMPTICK].ltime = t;
caster->lasttime[LT_NOMPTICK].interval = 1200L;
broadcast(caster->getSock(), caster->getRoom(), "%M collapses from exhaustion.", caster);
caster->print("You collapse from exhaustion.\n");
caster->knockUnconscious(60);
caster->mp.setCur(0);
}
newRoom = target->getRecallRoom().loadRoom(target);
if(newRoom) {
target->deleteFromRoom();
target->addToRoom(newRoom);
target->doPetFollow();
}
target->print("You have been %s!\n", ress ? "resurrected from the dead" : "fused with new blood");
target->hp.restore();
target->mp.restore();
target->pp.restore();
target->computeAttackPower();
target->computeAC();
target->clearAsEnemy();
target->save(true);
return(1);
}
//*********************************************************************
// splResurrect
//*********************************************************************
int splResurrect(Creature* player, cmd* cmnd, SpellData* spellData) {
if(spellData->how != CAST)
return(0);
if(!player->isDm()) {
if(player->getClass() != CLERIC && player->getDeity() != CERIS) {
player->print("You cannot cast that spell.\n");
return(0);
}
if(!player->spellIsKnown(S_RESURRECT)) {
player->print("You do not know that spell.\n");
return(0);
}
if(player->getLevel() < 19) {
player->print("You are not high enough level to cast that spell.\n");
return(0);
}
if(player->getAdjustedAlignment() != NEUTRAL) {
player->print("You must be neutral in order to cast that spell.\n");
return(0);
}
}
return(doRess(player, cmnd, true));
}
//*********************************************************************
// splBloodfusion
//*********************************************************************
int splBloodfusion(Creature* player, cmd* cmnd, SpellData* spellData) {
if(spellData->how != CAST)
return(0);
if(!player->isDm()) {
if(player->getClass() != CLERIC && player->getDeity() != ARAMON) {
player->print("You cannot cast that spell.\n");
return(0);
}
if(!player->spellIsKnown(S_BLOODFUSION)) {
player->print("You do not know that spell.\n");
return(0);
}
if(player->getLevel() < 22) {
player->print("You are not high enough level to cast that spell.\n");
return(0);
}
if(player->getAdjustedAlignment() != BLOODRED) {
player->print("You are not evil enough to cast that spell.\n");
return(0);
}
}
return(doRess(player, cmnd, false));
}
//*********************************************************************
// splRestore
//*********************************************************************
// This function allows a player to cast the restore spell using either
// a potion or a wand. Restore should not be a cast-able spell because
// it can restore magic points to full.
int splRestore(Creature* player, cmd* cmnd, SpellData* spellData) {
Creature* target=0;
if(spellData->how == CAST && player->isPlayer() && !player->isStaff()) {
player->print("You may not cast that spell.\n");
return(0);
}
// Cast restore on self
if(cmnd->num == 2) {
target = player;
if(spellData->how == CAST || spellData->how == WAND) {
player->print("Restore spell cast.\n");
broadcast(player->getSock(), player->getRoom(), "%M casts restore on %sself.", player, player->himHer());
} else if(spellData->how == POTION)
player->print("You feel restored.\n");
// Cast restore on another player
} else {
if(noPotion(player, spellData))
return(0);
cmnd->str[2][0] = up(cmnd->str[2][0]);
target = player->getRoom()->findCreature(player, cmnd->str[2], cmnd->val[2], false);
if(!target) {
player->print("That person is not here.\n");
return(0);
}
player->print("Restore spell cast on %N.\n", target);
target->print("%M casts a restore spell on you.\n", player);
broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M casts a restore spell on %N.",
player, target);
logCast(player, target, "restore");
}
addhp(target, dice(2, 10, 0));
if(mrand(1, 100) < 34)
target->mp.restore();
if(player->isStaff()) {
target->mp.restore();
target->hp.restore();
}
return(1);
}
//*********************************************************************
// splRoomVigor
//*********************************************************************
int splRoomVigor(Creature* player, cmd* cmnd, SpellData* spellData) {
int heal=0;
ctag *cp = player->getRoom()->first_ply, *cp_tmp=0;
if(spellData->how == POTION) {
player->print("The spell fizzles.\n");
return(0);
}
if(player->getClass() != CLERIC && !player->isCt()) {
player->print("Only clerics may cast that spell.\n");
return(0);
}
player->print("You cast vigor on everyone in the room.\n");
broadcast(player->getSock(), player->getRoom(), "%M casts vigor on everyone in the room.\n", player);
heal = mrand(1, 6) + bonus((int) player->piety.getCur());
if(player->getRoom()->magicBonus()) {
heal += mrand(1, 3);
player->print("\nThe room's magical properties increase the power of your spell\n");
}
while(cp) {
cp_tmp = cp->next_tag;
if(canCastHealing(player, cp->crt, false, false, false)) {
if(cp->crt != player)
cp->crt->print("%M casts vigor on you.\n", player);
addhp(cp->crt, heal);
if(cp->crt->inCombat(false))
player->smashInvis();
}
cp = cp_tmp;
}
return(1);
}