/* * ISpellMechanics.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "ISpellMechanics.h" #include "../CStack.h" #include "../battle/BattleInfo.h" #include "../NetPacks.h" #include "CDefaultSpellMechanics.h" #include "AdventureSpellMechanics.h" #include "BattleSpellMechanics.h" #include "CreatureSpellMechanics.h" BattleSpellCastParameters::Destination::Destination(const CStack * destination): stackValue(destination), hexValue(destination->position) { } BattleSpellCastParameters::Destination::Destination(const BattleHex & destination): stackValue(nullptr), hexValue(destination) { } BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell_) : spell(spell_), cb(cb), caster(caster), casterColor(caster->getOwner()), casterSide(cb->whatSide(casterColor)), casterHero(nullptr), mode(ECastingMode::HERO_CASTING), casterStack(nullptr), spellLvl(0), effectLevel(0), effectPower(0), enchantPower(0), effectValue(0) { casterStack = dynamic_cast(caster); casterHero = dynamic_cast(caster); spellLvl = caster->getSpellSchoolLevel(spell); effectLevel = caster->getEffectLevel(spell); effectPower = caster->getEffectPower(spell); effectValue = caster->getEffectValue(spell); enchantPower = caster->getEnchantPower(spell); vstd::amax(spellLvl, 0); vstd::amax(effectLevel, 0); vstd::amax(enchantPower, 0); vstd::amax(enchantPower, 0); vstd::amax(effectValue, 0); } BattleSpellCastParameters::BattleSpellCastParameters(const BattleSpellCastParameters & orig, const ISpellCaster * caster) :spell(orig.spell), cb(orig.cb), caster(caster), casterColor(caster->getOwner()), casterSide(cb->whatSide(casterColor)), casterHero(nullptr), mode(ECastingMode::MAGIC_MIRROR), casterStack(nullptr), spellLvl(orig.spellLvl), effectLevel(orig.effectLevel), effectPower(orig.effectPower), enchantPower(orig.enchantPower), effectValue(orig.effectValue) { casterStack = dynamic_cast(caster); casterHero = dynamic_cast(caster); } void BattleSpellCastParameters::aimToHex(const BattleHex& destination) { destinations.push_back(Destination(destination)); } void BattleSpellCastParameters::aimToStack(const CStack * destination) { if(nullptr == destination) logGlobal->error("BattleSpellCastParameters::aimToStack invalid stack."); else destinations.push_back(Destination(destination)); } void BattleSpellCastParameters::cast(const SpellCastEnvironment * env) { if(destinations.empty()) aimToHex(BattleHex::INVALID); spell->battleCast(env, *this); } bool BattleSpellCastParameters::castIfPossible(const SpellCastEnvironment * env) { if(ESpellCastProblem::OK == spell->canBeCast(cb, mode, caster)) { cast(env); return true; } return false; } BattleHex BattleSpellCastParameters::getFirstDestinationHex() const { if(destinations.empty()) { logGlobal->error("Spell have no destinations."); return BattleHex::INVALID; } return destinations.at(0).hexValue; } int BattleSpellCastParameters::getEffectValue() const { return (effectValue == 0) ? spell->calculateRawEffectValue(effectLevel, effectPower) : effectValue; } ///ISpellMechanics ISpellMechanics::ISpellMechanics(const CSpell * s): owner(s) { } std::unique_ptr ISpellMechanics::createMechanics(const CSpell * s) { switch (s->id) { case SpellID::ANTI_MAGIC: return make_unique(s); case SpellID::ACID_BREATH_DAMAGE: return make_unique(s); case SpellID::CHAIN_LIGHTNING: return make_unique(s); case SpellID::CLONE: return make_unique(s); case SpellID::CURE: return make_unique(s); case SpellID::DEATH_STARE: return make_unique(s); case SpellID::DISPEL: return make_unique(s); case SpellID::DISPEL_HELPFUL_SPELLS: return make_unique(s); case SpellID::EARTHQUAKE: return make_unique(s); case SpellID::FIRE_WALL: return make_unique(s); case SpellID::FORCE_FIELD: return make_unique(s); case SpellID::HYPNOTIZE: return make_unique(s); case SpellID::LAND_MINE: return make_unique(s); case SpellID::QUICKSAND: return make_unique(s); case SpellID::REMOVE_OBSTACLE: return make_unique(s); case SpellID::SACRIFICE: return make_unique(s); case SpellID::SUMMON_FIRE_ELEMENTAL: return make_unique(s, CreatureID::FIRE_ELEMENTAL); case SpellID::SUMMON_EARTH_ELEMENTAL: return make_unique(s, CreatureID::EARTH_ELEMENTAL); case SpellID::SUMMON_WATER_ELEMENTAL: return make_unique(s, CreatureID::WATER_ELEMENTAL); case SpellID::SUMMON_AIR_ELEMENTAL: return make_unique(s, CreatureID::AIR_ELEMENTAL); case SpellID::TELEPORT: return make_unique(s); default: if(s->isRisingSpell()) return make_unique(s); else return make_unique(s); } } //IAdventureSpellMechanics IAdventureSpellMechanics::IAdventureSpellMechanics(const CSpell * s): owner(s) { } std::unique_ptr IAdventureSpellMechanics::createMechanics(const CSpell * s) { switch (s->id) { case SpellID::SUMMON_BOAT: return make_unique(s); case SpellID::SCUTTLE_BOAT: return make_unique(s); case SpellID::DIMENSION_DOOR: return make_unique(s); case SpellID::FLY: case SpellID::WATER_WALK: case SpellID::VISIONS: case SpellID::DISGUISE: return make_unique(s); //implemented using bonus system case SpellID::TOWN_PORTAL: return make_unique(s); case SpellID::VIEW_EARTH: return make_unique(s); case SpellID::VIEW_AIR: return make_unique(s); default: return std::unique_ptr(); } }