/*
* effects.cpp
* Effects on creatures
* ____ _
* | _ \ ___ __ _| |_ __ ___ ___
* | |_) / _ \/ _` | | '_ ` _ \/ __|
* | _ < __/ (_| | | | | | | \__ \
* |_| \_\___|\__,_|_|_| |_| |_|___/
*
* 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 "effects.h"
#include "commands.h"
// C++ includes
#include <iomanip>
#include <locale>
//*********************************************************************
// getParentType
//*********************************************************************
EffectParentType Effects::getParentType(Creature* cParent, BaseRoom* rParent, Exit *xParent) {
if(xParent)
return(EFFECT_EXIT);
if(cParent)
return(EFFECT_CREATURE);
// rParent is also set for Exits, so check this last
if(rParent)
return(EFFECT_ROOM);
return(EFFECT_NO_PARENT);
}
//*********************************************************************
// EffectInfo
//*********************************************************************
EffectInfo::EffectInfo(bstring pName, time_t pLastMod, long pDuration, int pStrength, Creature* cParent, BaseRoom* rParent, Exit* xParent, const Creature* owner) {
myEffect = findEffect(pName, Effects::getParentType(cParent, rParent, xParent));
if(!myEffect)
throw bstring("Can't find effect " + pName);
name = pName;
setOwner(owner);
lastMod = pLastMod;
duration = pDuration;
strength = pStrength;
extra = 0;
parentCreature = cParent;
parentRoom = rParent;
parentExit = xParent;
}
EffectInfo::EffectInfo() {
parentCreature = 0;
parentRoom = 0;
myEffect = 0;
lastMod = 0;
duration = 0;
strength = 0;
extra = 0;
}
EffectInfo::EffectInfo(xmlNodePtr rootNode, EffectParentType type) {
xmlNodePtr curNode = rootNode->children;
extra = 0;
duration = 0;
strength = 0;
while(curNode) {
if(NODE_NAME(curNode, "Name")) xml::copyToBString(name, curNode);
else if(NODE_NAME(curNode, "Duration")) xml::copyToNum(duration, curNode);
else if(NODE_NAME(curNode, "Strength")) xml::copyToNum(strength, curNode);
else if(NODE_NAME(curNode, "Extra")) xml::copyToNum(extra, curNode);
curNode = curNode->next;
}
lastMod = time(0);
myEffect = findEffect(name, type);
if(!myEffect) {
throw bstring("Can't find effect listing " + name);
}
parentCreature = 0;
parentRoom = 0;
}
EffectInfo::~EffectInfo() {
}
AlcoholState getAlcoholState(const EffectInfo* effect) {
if(!effect || effect->getStrength() < 1)
return(ALCOHOL_SOBER);
if(effect->getStrength() < 20)
return(ALCOHOL_TIPSY);
if(effect->getStrength() < 66)
return(ALCOHOL_DRUNK);
return(ALCOHOL_INEBRIATED);
}
void EffectInfo::setParentCreature(Creature* parent) { parentCreature = parent; }
void EffectInfo::setParentRoom(BaseRoom* parent) { parentRoom = parent; }
void EffectInfo::setParentExit(Exit* parent) { parentExit = parent; }
effectPtr EffectInfo::getEffect() const { return(myEffect); }
const bstring& EffectInfo::getName() const { return(name); }
bstring EffectInfo::getDisplayName() const {
bstring displayName = myEffect->display;
if(myEffect->name != "drunkenness")
return(displayName);
// drunkenness has a different name based on strength
AlcoholState state = getAlcoholState(this);
if(state == ALCOHOL_SOBER)
displayName += "Sober"; // this state should never happen
else if(state == ALCOHOL_TIPSY)
displayName += "Tipsy";
else if(state == ALCOHOL_DRUNK)
displayName += "Drunk";
else if(state == ALCOHOL_INEBRIATED)
displayName += "Inebriated";
displayName += "^x";
return(displayName);
}
const bstring& EffectInfo::getOwner() const { return(pOwner); }
bool EffectInfo::isOwner(const Creature* owner) const {
// currently, only players can own effects
return(owner && owner->isPlayer() && pOwner == owner->name);
}
time_t EffectInfo::getLastMod() const { return(lastMod); }
long EffectInfo::getDuration() const { return(duration); }
int EffectInfo::getStrength() const { return(strength); }
int EffectInfo::getExtra() const { return(extra); }
bool EffectInfo::isPermanent() const { return(duration == -1); }
Creature* EffectInfo::getParentCreature() const { return(parentCreature); }
BaseRoom* EffectInfo::getParentRoom() const { return(parentRoom); }
Exit* EffectInfo::getParentExit() const { return(parentExit); }
void EffectInfo::setOwner(const Creature* owner) {
if(owner)
pOwner = owner->name;
else
pOwner = "";
}
void EffectInfo::setStrength(int pStrength) { strength = pStrength; }
void EffectInfo::setExtra(int pExtra) { extra = pExtra; }
void EffectInfo::setDuration(long pDuration) { duration = pDuration; }
//*********************************************************************
// willOverWrite
//*********************************************************************
// Will the given effect overwrite the existing effect?
bool EffectInfo::willOverWrite(EffectInfo* existingEffect) const {
// No effect, it'll overwrite :-P
if(!existingEffect)
return(true);
// Perm effects take presedence
if(duration == -1 && existingEffect->duration != -1)
return(true);
if(strength < existingEffect->strength)
return(false);
// Don't overwrite perm effects with non perm
if(existingEffect->duration == -1 && duration != -1)
return(false);
return(true);
}
//*********************************************************************
// operator<<
//*********************************************************************
std::ostream& operator<<(std::ostream& out, const EffectInfo& eff) {
out.setf(std::ios::right, std::ios::adjustfield);
bstring display = eff.getDisplayName();
short count=0;
int len = display.getLength();
for(int i=0; i<len; i++) {
if(display.getAt(i) == '^') {
count += 2;
i++;
}
}
out << std::setw(38+count) << display << " - ";
if(eff.duration == -1)
out << "Permanent!";
else
out << timeStr(eff.duration);
return(out);
}
//*********************************************************************
// pulse
//*********************************************************************
// True on a sucessful pulse
// False if it's time to wear off
bool EffectInfo::pulse(time_t t) {
ASSERTLOG(parentCreature || parentRoom);
bool wearOff = updateLastMod(t);
if(wearOff)
return(false);
if(myEffect && (myEffect->effFn))
return((*(myEffect->effFn))(this, parentCreature, EFFECT_PULSE, NULL, FROM_NOWHERE));
return(false);
}
//*********************************************************************
// updateLastMod
//*********************************************************************
// True if it's time for this effect to wear off
bool EffectInfo::updateLastMod(time_t t) {
time_t diff = t - lastMod;
lastMod = t;
diff = MIN(MAX(0, duration), diff);
duration -= diff;
return(duration == 0);
}
//*********************************************************************
// getRoom
//*********************************************************************
BaseRoom* EffectInfo::getRoom() const {
if(parentCreature)
return(parentCreature->getRoom());
return(parentRoom);
}
//*********************************************************************
// remove
//*********************************************************************
bool EffectInfo::remove(bool show) {
ASSERTLOG(parentCreature || parentRoom);
if(myEffect && (myEffect->effFn)) {
bool success = true;
if(show) {
if(parentCreature) {
if(!myEffect->selfStrDel.empty())
parentCreature->printColor("%s\n", myEffect->selfStrDel.c_str());
if(!myEffect->roomStrDel.empty() && getRoom())
broadcast(parentCreature->getSock(), getRoom(), myEffect->roomStrDel.c_str(), parentCreature);
} else if(parentExit) {
if(!myEffect->roomStrDel.empty() && getRoom())
broadcast(0, getRoom(), myEffect->roomStrDel.c_str(), parentExit->name);
} else {
if(!myEffect->roomStrDel.empty() && getRoom())
broadcast(0, getRoom(), myEffect->roomStrDel.c_str());
}
}
success &= (*(myEffect->effFn))(this, parentCreature, EFFECT_UNAPPLY, NULL, FROM_NOWHERE);
return(success);
}
return(false);
}
//*********************************************************************
// compute
//*********************************************************************
bool EffectInfo::compute(void* applier, ApplyFrom aFrom) {
ASSERTLOG(parentCreature || parentRoom);
if(!myEffect || !(myEffect->effFn))
return(false);
return((*(myEffect->effFn))(this, parentCreature, EFFECT_COMPUTE, applier, aFrom));
}
//*********************************************************************
// add
//*********************************************************************
bool EffectInfo::add() {
ASSERTLOG(parentCreature || parentRoom);
if(!myEffect || !(myEffect->effFn))
return(false);
if(parentCreature) {
if(!myEffect->selfStrAdd.empty())
parentCreature->printColor("%s\n", myEffect->selfStrAdd.c_str());
if(!myEffect->roomStrAdd.empty() && getRoom())
broadcast(parentCreature->getSock(), getRoom(), myEffect->roomStrAdd.c_str(), parentCreature);
} else if(parentExit) {
if(!myEffect->roomStrAdd.empty() && getRoom())
broadcast(0, getRoom(), myEffect->roomStrAdd.c_str(), parentExit->name);
} else {
if(!myEffect->roomStrAdd.empty() && getRoom())
broadcast(0, getRoom(), myEffect->roomStrAdd.c_str());
}
return(true);
}
//*********************************************************************
// apply
//*********************************************************************
bool EffectInfo::apply() {
ASSERTLOG(parentCreature || parentRoom);
if(!myEffect || !(myEffect->effFn))
return(false);
return((*(myEffect->effFn))(this, parentCreature, EFFECT_APPLY, NULL, FROM_NOWHERE));
}
// End - EffectInfo functions
//*********************************************************************
// addEffect
//*********************************************************************
bool Creature::addEffect(const bstring& effect, void* applier, ApplyFrom aFrom, bool show, const Creature* owner) {
return(effects.addEffect(effect, applier, aFrom, show, this, 0, 0, owner));
}
bool BaseRoom::addEffect(const bstring& effect, void* applier, ApplyFrom aFrom, bool show, const Creature* owner) {
return(effects.addEffect(effect, applier, aFrom, show, 0, this, 0, owner));
}
bool Exit::addEffect(const bstring& effect, void* applier, ApplyFrom aFrom, bool show, BaseRoom* rParent, const Creature* owner) {
return(effects.addEffect(effect, applier, aFrom, show, 0, rParent, this, owner));
}
bool Effects::addEffect(const bstring& effect, void* applier, ApplyFrom aFrom, bool show, Creature* cParent, BaseRoom* rParent, Exit* xParent, const Creature* owner) {
bool success = true;
EffectInfo* newEffect = new EffectInfo(effect, time(0), -1, 1, cParent, rParent, xParent, owner);
// Compute the effects potency, see if it will overwrite, and then apply & add
success = newEffect->compute(applier, aFrom);
if(success)
return(addEffect(newEffect, show, cParent, rParent, xParent));
return(false);
}
//*********************************************************************
// addEffect
//*********************************************************************
bool Creature::addEffect(const bstring& effect, long duration, int strength, bool show, const Creature* owner) {
return(effects.addEffect(effect, duration, strength, show, this, 0, 0, owner));
}
bool BaseRoom::addEffect(const bstring& effect, long duration, int strength, bool show, const Creature* owner) {
return(effects.addEffect(effect, duration, strength, show, 0, this, 0, owner));
}
bool Exit::addEffect(const bstring& effect, long duration, int strength, bool show, BaseRoom* rParent, const Creature* owner) {
return(effects.addEffect(effect, duration, strength, show, 0, rParent, this, owner));
}
bool Effects::addEffect(const bstring& effect, long duration, int strength, bool show, Creature* cParent, BaseRoom* rParent, Exit* xParent, const Creature* owner) {
if(!findEffect(effect, getParentType(cParent, rParent, xParent)))
return(false);
EffectInfo* newEffect = new EffectInfo(effect, time(0), duration, strength, cParent, rParent, xParent, owner);
return(addEffect(newEffect, show, cParent, rParent, xParent));
}
//*********************************************************************
// addEffect
//*********************************************************************
bool Creature::addEffect(EffectInfo* newEffect, bool show) {
return(effects.addEffect(newEffect, show, this));
}
bool BaseRoom::addEffect(EffectInfo* newEffect, bool show) {
return(effects.addEffect(newEffect, show, 0, this));
}
bool Exit::addEffect(EffectInfo* newEffect, bool show, BaseRoom* rParent) {
return(effects.addEffect(newEffect, show, 0, rParent, this));
}
bool Effects::addEffect(EffectInfo* newEffect, bool show, Creature* cParent, BaseRoom* rParent, Exit* xParent) {
newEffect->setParentCreature(cParent);
newEffect->setParentRoom(rParent);
newEffect->setParentExit(xParent);
EffectInfo* oldEffect = getEffect(newEffect->getName());
bool success = true;
if(oldEffect && !newEffect->willOverWrite(oldEffect)) {
// The new effect won't overwrite, so don't add it
if(cParent)
cParent->print("The effect didn't take hold.\n");
delete newEffect;
return(false);
}
// If no existing effect, or this one will overwrite remove the old one, and add the new one
removeEffect(newEffect->getName(), false, true, cParent, rParent, xParent); // Don't show the removal
if(show)
newEffect->add();
success &= newEffect->apply();
list.push_back(newEffect);
if(rParent)
rParent->addEffectsIndex();
return(true);
}
//*********************************************************************
// addPermEffect
//*********************************************************************
bool Creature::addPermEffect(const bstring& effect, int strength, bool show) {
return(effects.addEffect(effect, -1, strength, show, this));
}
bool BaseRoom::addPermEffect(const bstring& effect, int strength, bool show) {
return(effects.addEffect(effect, -1, strength, show, 0, this));
}
bool Exit::addPermEffect(const bstring& effect, int strength, bool show, BaseRoom* rParent) {
return(effects.addEffect(effect, -1, strength, show, 0, rParent, this));
}
//*********************************************************************
// removeEffect
//*********************************************************************
// Remove the effect (Won't remove permanent effects if remPerm is false)
bool Creature::removeEffect(const bstring& effect, bool show, bool remPerm) {
return(effects.removeEffect(effect, show, remPerm, this));
}
bool BaseRoom::removeEffect(const bstring& effect, bool show, bool remPerm) {
return(effects.removeEffect(effect, show, remPerm, 0, this));
}
bool Exit::removeEffect(const bstring& effect, bool show, bool remPerm, BaseRoom* rParent) {
return(effects.removeEffect(effect, show, remPerm, 0, rParent, this));
}
bool Effects::removeEffect(const bstring& effect, bool show, bool remPerm, Creature* cParent, BaseRoom* rParent, Exit* xParent) {
EffectInfo* toDel = getEffect(effect);
if(toDel && (toDel->getDuration() != -1 || (toDel->getDuration() == -1 && remPerm)))
return(removeEffect(toDel, show, cParent, rParent, xParent));
return(false);
}
//*********************************************************************
// removeEffect
//*********************************************************************
bool Creature::removeEffect(EffectInfo* toDel, bool show) {
return(effects.removeEffect(toDel, show, this));
}
bool BaseRoom::removeEffect(EffectInfo* toDel, bool show) {
return(effects.removeEffect(toDel, show, 0, this));
}
bool Exit::removeEffect(EffectInfo* toDel, bool show, BaseRoom* rParent) {
return(effects.removeEffect(toDel, show, 0, rParent, this));
}
bool Effects::removeEffect(EffectInfo* toDel, bool show, Creature* cParent, BaseRoom* rParent, Exit* xParent) {
if(!toDel)
return(false);
ASSERTLOG(toDel->getParentCreature() == cParent);
ASSERTLOG(toDel->getParentRoom() == rParent);
ASSERTLOG(toDel->getParentExit() == xParent);
list.remove(toDel);
toDel->remove(show);
delete toDel;
return(true);
}
//*********************************************************************
// removeOwner
//*********************************************************************
// on suicide, we remove the owner of the effect
void Effects::removeOwner(const Creature* owner) {
std::list<EffectInfo*>::iterator it;
for(it = list.begin() ; it != list.end() ; it++) {
if((*it)->isOwner(owner))
(*it)->setOwner(0);
}
}
//*********************************************************************
// isEffected
//*********************************************************************
bool Creature::isEffected(const bstring& effect) const {
return(effects.getEffect(effect) != NULL);
}
bool BaseRoom::isEffected(const bstring& effect) const {
return(effects.getEffect(effect) != NULL);
}
bool Exit::isEffected(const bstring& effect) const {
return(effects.getEffect(effect) != NULL);
}
//*********************************************************************
// hasPermEffect
//*********************************************************************
bool Creature::hasPermEffect(const bstring& effect) const {
EffectInfo* toCheck = effects.getEffect(effect);
return(toCheck && toCheck->getDuration() == -1);
}
bool BaseRoom::hasPermEffect(const bstring& effect) const {
EffectInfo* toCheck = effects.getEffect(effect);
return(toCheck && toCheck->getDuration() == -1);
}
bool Exit::hasPermEffect(const bstring& effect) const {
EffectInfo* toCheck = effects.getEffect(effect);
return(toCheck && toCheck->getDuration() == -1);
}
//*********************************************************************
// getEffect
//*********************************************************************
EffectInfo* Creature::getEffect(const bstring& effect) const {
return(effects.getEffect(effect));
}
EffectInfo* BaseRoom::getEffect(const bstring& effect) const {
return(effects.getEffect(effect));
}
EffectInfo* Exit::getEffect(const bstring& effect) const {
return(effects.getEffect(effect));
}
EffectInfo* Effects::getEffect(const bstring& effect) const {
std::list<EffectInfo*>::const_iterator eIt;
for(eIt = list.begin() ; eIt != list.end() ; eIt++) {
if((*eIt) && (*eIt)->getName() == effect)
return((*eIt));
}
return(NULL);
}
//*********************************************************************
// pulseEffects
//*********************************************************************
// Pulse all effects on this creature
// return false if creature died because of this
bool Creature::pulseEffects(time_t t) {
bool pulsed = true;
bool poison = false;
EffectInfo* effect=0;
std::list<EffectInfo*>::iterator eIt;
deathtype = DT_NONE;
for(eIt = effects.list.begin() ; eIt != effects.list.end() ;) {
effect = (*eIt);
// Pulse!
ASSERTLOG(effect->getParentCreature() == this);
pulsed = effect->pulse(t);
// If pulse returns false, purge this effect
if(!pulsed) {
effect->remove();
if(poison || effect->isPoison())
poison = true;
delete effect;
eIt = effects.list.erase(eIt);
} else
eIt++;
}
// pulse effects might kill them
if(deathtype != DT_NONE && hp.getCur() < 1) {
if(isPlayer())
getPlayer()->die(deathtype);
else
getMonster()->mobDeath();
return(false);
}
// if they're not poisoned anymore, clear poison
if(poison && !isPoisoned())
curePoison();
return(true);
}
//*********************************************************************
// pulseEffects
//*********************************************************************
bool BaseRoom::pulseEffects(time_t t) {
effects.pulse(t, this);
xtag* xp = first_ext;
while(xp) {
xp->ext->pulseEffects(t, this);
xp = xp->next_tag;
}
return(true);
}
//*********************************************************************
// pulseEffects
//*********************************************************************
bool Exit::pulseEffects(time_t t, BaseRoom* rParent) {
effects.pulse(t, rParent, this);
return(true);
}
//*********************************************************************
// pulse
//*********************************************************************
// generic pulse function that can be used on rooms and exits (because
// they can't die like players can)
void Effects::pulse(time_t t, BaseRoom* rParent, Exit* xParent) {
std::list<EffectInfo*>::iterator it;
EffectInfo* effect=0;
bool pulsed=false;
for(it = list.begin() ; it != list.end() ;) {
effect = (*it);
// Pulse!
ASSERTLOG(effect->getParentRoom() == rParent);
ASSERTLOG(effect->getParentExit() == xParent);
pulsed = effect->pulse(t);
// If pulse returns false, purge this effect
if(!pulsed) {
effect->remove();
delete effect;
it = list.erase(it);
} else
it++;
}
}
//*********************************************************************
// removeAll
//*********************************************************************
void Effects::removeAll() {
EffectInfo* effect=0;
std::list<EffectInfo*>::iterator eIt;
for(eIt = list.begin() ; eIt != list.end() ; eIt++) {
effect = (*eIt);
delete effect;
(*eIt) = NULL;
}
list.clear();
}
//*********************************************************************
// copy
//*********************************************************************
void Effects::copy(const Effects* source, Creature* cParent) {
EffectInfo* effect;
std::list<EffectInfo*>::const_iterator eIt;
for(eIt = source->list.begin() ; eIt != source->list.end() ; eIt++) {
effect = new EffectInfo();
(*effect) = *(*eIt);
effect->setParentCreature(cParent);
list.push_back(effect);
}
}
//*********************************************************************
// cmdEffects
//*********************************************************************
int cmdEffects(Creature* creature, cmd* cmnd) {
Creature* target = creature;
int num=0;
if(creature->isCt()) {
if(cmnd->num > 1) {
target = creature->getRoom()->findCreature(creature, cmnd);
cmnd->str[1][0] = up(cmnd->str[1][0]);
if(!target) {
target = gServer->findPlayer(cmnd->str[1]);
if(!target || !creature->canSee(target)) {
creature->print("Target not found.\n");
return(0);
}
}
}
}
num = target->effects.list.size();
creature->print("Current Effects for %s:\n", target->name);
creature->printColor("%s", target->effects.getEffectsString(creature).c_str());
creature->print("\n%d effect%s found.\n", num, num != 1 ? "s" : "");
return(0);
}
//*********************************************************************
// getEffectsList
//*********************************************************************
// Return a list of effects
bstring Effects::getEffectsList() const {
std::ostringstream effStr;
effStr << "Effects: ";
int num = 0;
const EffectInfo* effect;
std::list<EffectInfo*>::const_iterator eIt;
for(eIt = list.begin() ; eIt != list.end() ; eIt++) {
effect = (*eIt);
if(num != 0)
effStr << ", ";
effStr << effect->getName();
num++;
}
if(num == 0)
effStr << "None";
effStr << ".\n";
bstring toPrint = effStr.str();
return(toPrint);
}
//*********************************************************************
// getEffectsString
//*********************************************************************
// Used to print out what effects a creature is under
bstring Effects::getEffectsString(const Creature* viewer) {
std::ostringstream effStr;
long t = time(0);
EffectInfo* effect=0;
std::list<EffectInfo*>::iterator eIt;
for(eIt = list.begin() ; eIt != list.end() ; eIt++) {
effect = (*eIt);
effect->updateLastMod(t);
effStr << *effect;
if(viewer->isStaff()) {
effStr << " ^WStrength: " << effect->getStrength();
if(effect->getExtra())
effStr << " ^WExtra: " << effect->getExtra();
}
effStr << "\n";
}
return(effStr.str());
}
//*********************************************************************
// convertOldEffects
//*********************************************************************
// This function will convert flag/lt combos into effects
void Creature::convertOldEffects() {
Player* pPlayer = getPlayer();
Monster* mMonster = getMonster();
if(version < "2.40") {
if(mMonster) {
// mMonster->convertToEffect("stoneskin", OLD_M_STONESKIN, -1);
// mMonster->convertToEffect("invisibility", OLD_M_INVISIBLE, OLD_LT_INVISIBILITY);
} else if(pPlayer) {
}
}
}
//*********************************************************************
// convertToEffect
//*********************************************************************
// Convert the given effect from a flag/lt to an effect
bool Creature::convertToEffect(const bstring& effect, int flag, int lt) {
if(!flagIsSet(flag))
return(false);
clearFlag(flag);
long duration = 0;
if(lt != -1 && lasttime[lt].interval != 0)
duration = lasttime[lt].interval;
else
duration = -1;
EffectInfo* newEffect = new EffectInfo(effect, time(0), duration, 1, this);
// if(lt != -1 && (effect == "armor" || effect == "stoneskin")) {
// newEffect->setStrength(lasttime[lt].misc);
// }
// Assuming that they're already properly under the effect, so just add it to the list
// and don't actually add it or compute it.
// IE: Strength buff -- they already have +str, so don't give them more str!!
effects.list.push_back(newEffect);
return(true);
}
//*********************************************************************
// removeOppositeEffect
//*********************************************************************
bool Creature::removeOppositeEffect(const EffectInfo *effect) {
return(effects.removeOppositeEffect(effect, this));
}
bool BaseRoom::removeOppositeEffect(const EffectInfo *effect) {
return(effects.removeOppositeEffect(effect, 0, this));
}
bool Exit::removeOppositeEffect(const EffectInfo *effect, BaseRoom* rParent) {
return(effects.removeOppositeEffect(effect, 0, rParent, this));
}
bool Effects::removeOppositeEffect(const EffectInfo *effect, Creature* cParent, BaseRoom* rParent, Exit* xParent) {
effectPtr parentEffect = effect->getEffect();
if(!parentEffect)
return(false);
if(parentEffect->oppositeEffect.empty())
return(false);
return(removeEffect(parentEffect->oppositeEffect, true, true, cParent, rParent, xParent));
}
//*********************************************************************
// addStatModEffect
//*********************************************************************
bool Creature::addStatModEffect(EffectInfo* effect) {
Stat* stat=0;
Player* pThis = getPlayer();
bool good;
int hpMod = 0;
int mpMod = 0;
if(effect->getName() == "strength") {
if(pThis) {
if(flagIsSet(P_BERSERKED))
pThis->loseRage();
if(cClass == DEATHKNIGHT && flagIsSet(P_PRAYED))
pThis->losePray();
}
good = true;
stat = &strength;
} else if(effect->getName() == "enfeeblement") {
good = false;
stat = &strength;
} else if(effect->getName() == "haste") {
if(pThis && flagIsSet(P_FRENZY))
pThis->loseFrenzy();
good = true;
stat = &dexterity;
} else if(effect->getName() == "slow") {
good = false;
stat = &dexterity;
} else if(effect->getName() == "insight") {
if(pThis && isEffected("confusion"))
pThis->removeEffect("confusion");
good = true;
mpMod = (int)(level * 1.5);
stat = &intelligence;
} else if(effect->getName() == "feeblemind") {
good = false;
mpMod = (int)(level * -1.5);
stat = &intelligence;
} else if(effect->getName() == "prayer") {
if(pThis && cClass != DEATHKNIGHT && flagIsSet(P_PRAYED))
pThis->losePray();
good = true;
stat = &piety;
} else if(effect->getName() == "damnation") {
good = false;
stat = &piety;
} else if(effect->getName() == "fortitude") {
good = true;
hpMod = (int)(level * 1.5);
stat = &constitution;
} else if(effect->getName() == "weakness") {
good = false;
hpMod = (int)(level * -1.5);
stat = &constitution;
} else {
print("Unknown stat effect: %s\n", effect->getName().c_str());
return(false);
}
int addAmt = effect->getStrength();
if(good == false && addAmt > 0)
addAmt *= -1;
// print("StatAdd: %s PreAdjust: %d", effect->getName().c_str(), addAmt);
if(stat->getCur() + addAmt > MAX_STAT_NUM)
addAmt = MAX(0, MAX_STAT_NUM - stat->getCur());
else if(stat->getCur() + addAmt < 1)
addAmt = 0 - (stat->getCur() - 1);
// print(" PostAdjust: %d\n", addAmt);
effect->setStrength(addAmt);
stat->addCur(addAmt);
if(hpMod) {
hpMod = hp.adjustMax(hpMod);
effect->setExtra(hpMod);
if(hpMod > 0)
hp.adjust(hpMod);
} else if(mpMod) {
mpMod = mp.adjustMax(mpMod);
effect->setExtra(mpMod);
if(mpMod > 0)
mp.adjust(mpMod);
}
if(pThis) {
pThis->computeAttackPower();
pThis->computeAC();
}
return(true);
}
//*********************************************************************
// remStatModEffect
//*********************************************************************
bool Creature::remStatModEffect(EffectInfo* effect) {
Stat* stat=0;
Player* pThis = getPlayer();
int hpMod = 0;
int mpMod = 0;
if(effect->getName() == "strength") {
stat = &strength;
} else if(effect->getName() == "enfeeblement") {
stat = &strength;
} else if(effect->getName() == "haste") {
stat = &dexterity;
} else if(effect->getName() == "slow") {
stat = &dexterity;
} else if(effect->getName() == "insight") {
mpMod = -1 * effect->getExtra();
stat = &intelligence;
} else if(effect->getName() == "feeblemind") {
mpMod = -1 * effect->getExtra();
stat = &intelligence;
} else if(effect->getName() == "prayer") {
stat = &piety;
} else if(effect->getName() == "damnation") {
stat = &piety;
} else if(effect->getName() == "fortitude") {
hpMod = -1 * effect->getExtra();
stat = &constitution;
} else if(effect->getName() == "weakness") {
hpMod = -1 * effect->getExtra();
stat = &constitution;
} else {
print("Unknown stat effect: %s\n", effect->getName().c_str());
return(false);
}
int adjAmt = -1 * effect->getStrength();
// if(good == false && adjAmt > 0)
// adjAmt *= -1;
if(stat->getCur() - adjAmt > MAX_STAT_NUM)
adjAmt = MAX(0, MAX_STAT_NUM - stat->getCur());
else if(stat->getCur() - adjAmt < 1)
adjAmt = 0 - (stat->getCur() - 1);
effect->setStrength(adjAmt);
stat->adjust(adjAmt);
if(hpMod) {
hp.adjustMax(hpMod);
if(hpMod > 0)
hp.adjust(hpMod);
} else if(mpMod) {
mp.adjustMax(mpMod);
if(mpMod > 0)
mp.adjust(mpMod);
}
if(pThis) {
pThis->computeAttackPower();
pThis->computeAC();
}
return(true);
}
//*********************************************************************
// exitEffectDamage
//*********************************************************************
// Wrapper to actually do the damage to the target
// Return: true if they were killed
bool exitEffectDamage(EffectInfo *effect, Creature* target, Creature* owner, Realm realm, DeathType dt, const char* crtStr, const char* deathStr, const char* roomStr, const char* killerStr) {
Damage damage;
if(!effect || effect->getExtra() || effect->isOwner(owner))
return(false);
Player* killer=0;
bool online = true;
if(effect->getOwner() != "") {
killer = gServer->findPlayer(effect->getOwner());
if(!killer) {
if(loadPlayer(effect->getOwner().c_str(), &killer))
online = false;
else
killer = 0;
}
}
damage.set(mrand(effect->getStrength() / 2, effect->getStrength() * 3 / 2));
target->modifyDamage(0, MAGICAL, damage, realm);
if(killer && target->isMonster()) {
target->getMonster()->addEnmCrt(killer);
if(online)
target->getMonster()->addEnmDmg(killer, damage.get());
}
target->printColor(crtStr, target->customColorize("*CC:DAMAGE*"), damage.get());
target->hp.decrease(damage.get());
if(target->hp.getCur() < 1) {
target->print(deathStr);
broadcast(target->getSock(), target->getRoom(), roomStr, target, target);
if(killer) {
if(online)
killer->print(killerStr, target);
target->die(killer);
killer->save(online);
if(!online)
free_crt(killer);
} else {
if(target->isPlayer())
target->getPlayer()->die(dt);
else
target->getMonster()->mobDeath();
}
return(true);
}
if(killer && !online)
free_crt(killer);
return(false);
}
//*********************************************************************
// doEffectDamage
//*********************************************************************
// Return: true if they were killed
bool Exit::doEffectDamage(Creature* target) {
Creature *owner = target;
if(target->isPet())
owner = target->following;
if( exitEffectDamage(
getEffect("wall-of-fire"),
target, owner, FIRE, BURNED,
"The wall of fire burns you for %s%d^x damage.\n",
"You are burned to death!\n",
"%1M steps through the wall of fire.\n%M burns to death!",
"%M steps through your wall of fire and is incinerated!\n"
) )
return(true);
if( exitEffectDamage(
getEffect("wall-of-thorns"),
target, owner, EARTH, THORNS,
"The wall of thorns stabs you for %s%d^x damage.\n",
"You are stabbed to death!\n",
"%1M steps through a wall of thorns.\n%M is stabbed to death!",
"%M steps through your wall of thorns and is stabbed to death!\n"
) )
return(true);
return(false);
}