From 2b434111bf5a3d6ba906c44f0581f562f97a5588 Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Thu, 17 Sep 2015 08:42:30 +0300 Subject: [PATCH] More hero|creature casting unification --- client/battle/CBattleInterface.cpp | 4 +- lib/BattleState.cpp | 23 ++++++++++++ lib/BattleState.h | 12 ++++++ lib/CGameInfoCallback.cpp | 2 +- lib/mapObjects/CGHeroInstance.cpp | 22 +++++++++++ lib/mapObjects/CGHeroInstance.h | 12 ++++++ lib/spells/BattleSpellMechanics.cpp | 2 + lib/spells/CDefaultSpellMechanics.cpp | 51 +++---------------------- lib/spells/CDefaultSpellMechanics.h | 2 - lib/spells/CSpellHandler.cpp | 4 +- lib/spells/ISpellMechanics.cpp | 30 ++++++++++++--- lib/spells/ISpellMechanics.h | 29 +++++++------- lib/spells/Magic.h | 18 ++++++++- server/CGameHandler.cpp | 54 ++++++++++----------------- 14 files changed, 159 insertions(+), 106 deletions(-) diff --git a/client/battle/CBattleInterface.cpp b/client/battle/CBattleInterface.cpp index 663cdcf5f..dd3394081 100644 --- a/client/battle/CBattleInterface.cpp +++ b/client/battle/CBattleInterface.cpp @@ -2103,9 +2103,9 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType) { ui8 skill = 0; if (creatureCasting) - skill = sactive->getSpellSchoolLevel(SpellID(SpellID::TELEPORT).toSpell()); + skill = sactive->getEffectLevel(SpellID(SpellID::TELEPORT).toSpell()); else - skill = getActiveHero()->getSpellSchoolLevel (CGI->spellh->objects[spellToCast->additionalInfo]); + skill = getActiveHero()->getEffectLevel(SpellID(SpellID::TELEPORT).toSpell()); //TODO: explicitely save power, skill if (curInt->cb->battleCanTeleportTo(selectedStack, myNumber, skill)) legalAction = true; diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index b92770850..b8d9aff93 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -1196,6 +1196,29 @@ ui32 CStack::getSpellBonus(const CSpell * spell, ui32 base, const CStack * affec return base; } +int CStack::getEffectLevel(const CSpell * spell) const +{ + return getSpellSchoolLevel(spell); +} + +int CStack::getEffectPower(const CSpell * spell) const +{ + return valOfBonuses(Bonus::CREATURE_SPELL_POWER) * count / 100; +} + +int CStack::getEnchantPower(const CSpell * spell) const +{ + int res = valOfBonuses(Bonus::CREATURE_ENCHANT_POWER); + if(res<=0) + res = 3;//default for creatures + return res; +} + +int CStack::getEffectValue(const CSpell * spell) const +{ + return valOfBonuses(Bonus::SPECIFIC_SPELL_POWER, spell->id.toEnum()) * count; +} + bool CMP_stack::operator()( const CStack* a, const CStack* b ) { switch(phase) diff --git a/lib/BattleState.h b/lib/BattleState.h index 512d03e46..60716cfb2 100644 --- a/lib/BattleState.h +++ b/lib/BattleState.h @@ -235,6 +235,18 @@ public: ///ISpellCaster ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const override; ui32 getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const override; + + ///default spell school level for effect calculation + int getEffectLevel(const CSpell * spell) const override; + + ///default spell-power for damage/heal calculation + int getEffectPower(const CSpell * spell) const override; + + ///default spell-power for timed effects duration + int getEnchantPower(const CSpell * spell) const override; + + ///damage/heal override(ignores spell configuration, effect level and effect power) + int getEffectValue(const CSpell * spell) const override; template void serialize(Handler &h, const int version) { diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index 2a59b96d3..7943f2dd9 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -173,7 +173,7 @@ int CGameInfoCallback::estimateSpellDamage(const CSpell * sp, const CGHeroInstan ERROR_RET_VAL_IF(hero && !canGetFullInfo(hero), "Cannot get info about caster!", -1); if (hero) //we see hero's spellbook - return sp->calculateDamage(hero, nullptr, hero->getSpellSchoolLevel(sp), hero->getPrimSkillLevel(PrimarySkill::SPELL_POWER)); + return sp->calculateDamage(hero, nullptr, hero->getEffectLevel(sp), hero->getEffectPower(sp)); else return 0; //mage guild } diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 06842abd6..05d1d62aa 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -902,6 +902,28 @@ ui32 CGHeroInstance::getSpellBonus(const CSpell * spell, ui32 base, const CStack return base; } +int CGHeroInstance::getEffectLevel(const CSpell * spell) const +{ + if(hasBonusOfType(Bonus::MAXED_SPELL, spell->id)) + return 3;//todo: recheck specialty from where this bonus is. possible bug + else + return getSpellSchoolLevel(spell); +} + +int CGHeroInstance::getEffectPower(const CSpell * spell) const +{ + return getPrimSkillLevel(PrimarySkill::SPELL_POWER); +} + +int CGHeroInstance::getEnchantPower(const CSpell * spell) const +{ + return getPrimSkillLevel(PrimarySkill::SPELL_POWER) + valOfBonuses(Bonus::SPELL_DURATION); +} + +int CGHeroInstance::getEffectValue(const CSpell * spell) const +{ + return 0; +} bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const { diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index 85fe26692..26583f874 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -210,6 +210,18 @@ public: ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const override; ui32 getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const override; + ///default spell school level for effect calculation + int getEffectLevel(const CSpell * spell) const override; + + ///default spell-power for damage/heal calculation + int getEffectPower(const CSpell * spell) const override; + + ///default spell-power for timed effects duration + int getEnchantPower(const CSpell * spell) const override; + + ///damage/heal override(ignores spell configuration, effect level and effect power) + int getEffectValue(const CSpell * spell) const override; + void deserializationFix(); void initObj() override; diff --git a/lib/spells/BattleSpellMechanics.cpp b/lib/spells/BattleSpellMechanics.cpp index 94b272ccd..d32d596a2 100644 --- a/lib/spells/BattleSpellMechanics.cpp +++ b/lib/spells/BattleSpellMechanics.cpp @@ -636,6 +636,8 @@ void SummonMechanics::applyBattleEffects(const SpellCastEnvironment * env, Battl ///TeleportMechanics void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const { + //todo: check legal teleport + BattleStackMoved bsm; bsm.distance = -1; bsm.stack = parameters.selectedStack->ID; diff --git a/lib/spells/CDefaultSpellMechanics.cpp b/lib/spells/CDefaultSpellMechanics.cpp index 24fcd5ea1..3b4adacce 100644 --- a/lib/spells/CDefaultSpellMechanics.cpp +++ b/lib/spells/CDefaultSpellMechanics.cpp @@ -223,38 +223,15 @@ ESpellCastResult DefaultSpellMechanics::applyAdventureEffects(const SpellCastEnv void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const { - logGlobal->debugStream() << "Started spell cast. Spell: "<name<<"; mode:"<debugStream() << "Started spell cast. Spell: "<name<<"; mode:"<valOfBonuses(Bonus::CREATURE_ENCHANT_POWER);; - if(parameters.enchantPower == 0) - parameters.enchantPower = 3; //default for creatures - //Fairy Dragon, etc. - int effectPower = parameters.casterStack->valOfBonuses(Bonus::CREATURE_SPELL_POWER) * parameters.casterStack->count / 100; - if(parameters.effectPower == 0) - parameters.effectPower = effectPower; - //Archangel, etc - int unitSpellPower = parameters.casterStack->valOfBonuses(Bonus::SPECIFIC_SPELL_POWER, owner->id.toEnum()); - if(parameters.effectValue == 0) - parameters.effectValue = parameters.casterStack->count * unitSpellPower; - } - else if (parameters.casterHero) - { - if(parameters.enchantPower == 0) - parameters.enchantPower = parameters.casterHero->getPrimSkillLevel(PrimarySkill::SPELL_POWER) + parameters.casterHero->valOfBonuses(Bonus::SPELL_DURATION); - if(parameters.effectPower == 0) - parameters.effectPower = parameters.casterHero->getPrimSkillLevel(PrimarySkill::SPELL_POWER); - } - else + if(nullptr == parameters.caster) { env->complain("No spell-caster provided."); return; } + + const ISpellCaster * caster = parameters.caster; BattleSpellCast sc; prepareBattleCast(parameters, sc); @@ -331,11 +308,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS StacksInjured si; SpellCastContext ctx(attackedCres, sc, si); - - if(parameters.casterStack) - ctx.caster = parameters.casterStack; - else if(parameters.casterHero) - ctx.caster = parameters.casterHero; + ctx.caster = caster; applyBattleEffects(env, parameters, ctx); @@ -505,20 +478,6 @@ void DefaultSpellMechanics::battleLogSingleTarget(std::vector & log } } -int DefaultSpellMechanics::calculateEffectLevel(const BattleSpellCastParameters& parameters) const -{ - int effectLevel = parameters.spellLvl; - { - //MAXED_SPELL bonus. - if(parameters.casterHero != nullptr) - if(parameters.casterHero->hasBonusOfType(Bonus::MAXED_SPELL, owner->id)) - effectLevel = 3; - } - - return effectLevel; -} - - void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const { //applying effects diff --git a/lib/spells/CDefaultSpellMechanics.h b/lib/spells/CDefaultSpellMechanics.h index efdf6d6e8..cf4e3bf24 100644 --- a/lib/spells/CDefaultSpellMechanics.h +++ b/lib/spells/CDefaultSpellMechanics.h @@ -58,8 +58,6 @@ public: protected: virtual void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const; - int calculateEffectLevel(const BattleSpellCastParameters & parameters) const; - ///actual adventure cast implementation virtual ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const; diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index fe43b01a1..130cb349f 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -26,7 +26,9 @@ #include "../mapObjects/CGHeroInstance.h" #include "../BattleState.h" #include "../CBattleCallback.h" -#include "../CGameState.h" +#include "../CGameState.h" //todo: remove + +#include "../NetPacks.h" //todo: remove #include "ISpellMechanics.h" diff --git a/lib/spells/ISpellMechanics.cpp b/lib/spells/ISpellMechanics.cpp index 19089b844..30b736d23 100644 --- a/lib/spells/ISpellMechanics.cpp +++ b/lib/spells/ISpellMechanics.cpp @@ -11,20 +11,40 @@ #include "StdInc.h" #include "ISpellMechanics.h" +#include "../BattleState.h" +#include "../NetPacks.h" + #include "CDefaultSpellMechanics.h" #include "AdventureSpellMechanics.h" #include "BattleSpellMechanics.h" #include "CreatureSpellMechanics.h" -BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo* cb) - : spellLvl(0), destination(BattleHex::INVALID), casterSide(0),casterColor(PlayerColor::CANNOT_DETERMINE),casterHero(nullptr), - mode(ECastingMode::HERO_CASTING), casterStack(nullptr), selectedStack(nullptr), cb(cb), - effectLevel(0), effectPower(0), enchantPower(0), effectValue(0) +BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell) + : cb(cb), caster(caster), casterSide(0),casterColor(PlayerColor::CANNOT_DETERMINE), + spellLvl(-1), destination(BattleHex::INVALID),casterHero(nullptr), + mode(ECastingMode::HERO_CASTING), casterStack(nullptr), selectedStack(nullptr), + effectLevel(-1), effectPower(0), enchantPower(0), effectValue(0) { - + casterStack = dynamic_cast(caster); + casterHero = dynamic_cast(caster); + prepare(spell); } +void BattleSpellCastParameters::prepare(const CSpell * spell) +{ + 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); +} ///ISpellMechanics ISpellMechanics::ISpellMechanics(CSpell * s): diff --git a/lib/spells/ISpellMechanics.h b/lib/spells/ISpellMechanics.h index 4a8f2088b..a247bc36a 100644 --- a/lib/spells/ISpellMechanics.h +++ b/lib/spells/ISpellMechanics.h @@ -12,8 +12,7 @@ #include "CSpellHandler.h" #include "../BattleHex.h" -#include "../BattleState.h" -#include "../NetPacks.h" + ///callback to be provided by server class DLL_LINKAGE SpellCastEnvironment @@ -35,26 +34,30 @@ public: struct DLL_LINKAGE BattleSpellCastParameters { public: - BattleSpellCastParameters(const BattleInfo * cb); - ///spell school level , 0-use default + BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell); + const BattleInfo * cb; + const ISpellCaster * caster; + ui8 casterSide; + PlayerColor casterColor; + ///spell school level , -1-use default int spellLvl; BattleHex destination; - ui8 casterSide; - PlayerColor casterColor; const CGHeroInstance * casterHero; //deprecated ECastingMode::ECastingMode mode; - const CStack * casterStack; + const CStack * casterStack; //deprecated const CStack * selectedStack; - const BattleInfo * cb; + - ///spell school level to use for effects, 0-use spellLvl + ///spell school level to use for effects int effectLevel; - ///actual spell-power affecting effect values, 0-use default + ///actual spell-power affecting effect values int effectPower; - ///actual spell-power affecting effect duration, 0-use default + ///actual spell-power affecting effect duration int enchantPower; - ///for Archangel-like casting, 0-use default - int effectValue; + ///for Archangel-like casting + int effectValue; +private: + void prepare(const CSpell * spell); }; struct DLL_LINKAGE AdventureSpellCastParameters diff --git a/lib/spells/Magic.h b/lib/spells/Magic.h index f31dad546..bfedf881d 100644 --- a/lib/spells/Magic.h +++ b/lib/spells/Magic.h @@ -26,7 +26,21 @@ public: /// returns level on which given spell would be cast by this(0 - none, 1 - basic etc); /// caster may not know this spell at all /// optionally returns number of selected school by arg - 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic - virtual ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const = 0; - + virtual ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const = 0; + + ///applying sorcery secondary skill etc virtual ui32 getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const = 0; + + ///default spell school level for effect calculation + virtual int getEffectLevel(const CSpell * spell) const = 0; + + ///default spell-power for damage/heal calculation + virtual int getEffectPower(const CSpell * spell) const = 0; + + ///default spell-power for timed effects duration + virtual int getEnchantPower(const CSpell * spell) const = 0; + + ///damage/heal override(ignores spell configuration, effect level and effect power) + virtual int getEffectValue(const CSpell * spell) const = 0; + }; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index ef1b0a3d3..32bd6e315 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -3868,24 +3868,20 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) complain("That stack can't cast spells!"); else { - BattleSpellCastParameters parameters(gs->curB); - + const CSpell * spell = SpellID(spellID).toSpell(); + BattleSpellCastParameters parameters(gs->curB, stack, spell); parameters.spellLvl = 0; if (spellcaster) vstd::amax(parameters.spellLvl, spellcaster->val); if (randSpellcaster) vstd::amax(parameters.spellLvl, randSpellcaster->val); vstd::amin (parameters.spellLvl, 3); - + parameters.effectLevel = parameters.spellLvl; parameters.casterSide = gs->curB->whatSide(stack->owner); parameters.mode = ECastingMode::CREATURE_ACTIVE_CASTING; parameters.destination = destination; parameters.casterColor = stack->owner; - parameters.casterHero = nullptr; - parameters.casterStack = stack; - parameters.selectedStack = nullptr; - - const CSpell * spell = SpellID(spellID).toSpell(); + parameters.selectedStack = nullptr; spell->battleCast(spellEnv, parameters); } sendAndApply(&end_action); @@ -4074,14 +4070,11 @@ bool CGameHandler::makeCustomAction( BattleAction &ba ) const CSpell * s = SpellID(ba.additionalInfo).toSpell(); - BattleSpellCastParameters parameters(gs->curB); - parameters.spellLvl = h->getSpellSchoolLevel(s); + BattleSpellCastParameters parameters(gs->curB, h, s); parameters.destination = ba.destinationTile; parameters.casterSide = ba.side; parameters.casterColor = h->tempOwner; - parameters.casterHero = h; parameters.mode = ECastingMode::HERO_CASTING; - parameters.casterStack = nullptr; parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false); ESpellCastProblem::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h->tempOwner, s, ECastingMode::HERO_CASTING); @@ -4230,14 +4223,13 @@ void CGameHandler::stackTurnTrigger(const CStack * st) if (gs->curB->battleCanCastThisSpell(st->owner, spell, ECastingMode::ENCHANTER_CASTING) == ESpellCastProblem::OK) { - BattleSpellCastParameters parameters(gs->curB); + BattleSpellCastParameters parameters(gs->curB, st, spell); parameters.spellLvl = bonus->val; + parameters.effectLevel = bonus->val;//todo: recheck parameters.destination = BattleHex::INVALID; parameters.casterSide = side; parameters.casterColor = st->owner; - parameters.casterHero = nullptr; parameters.mode = ECastingMode::ENCHANTER_CASTING; - parameters.casterStack = st; parameters.selectedStack = nullptr; spell->battleCast(spellEnv, parameters); @@ -4942,14 +4934,13 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta { const CSpell * spell = SpellID(spellID).toSpell(); - BattleSpellCastParameters parameters(gs->curB); + BattleSpellCastParameters parameters(gs->curB, attacker, spell); parameters.spellLvl = spellLevel; + parameters.effectLevel = spellLevel; parameters.destination = destination; parameters.casterSide = !attacker->attackerOwned; parameters.casterColor = attacker->owner; - parameters.casterHero = nullptr; parameters.mode = ECastingMode::AFTER_ATTACK_CASTING; - parameters.casterStack = attacker; parameters.selectedStack = nullptr; spell->battleCast(spellEnv, parameters); @@ -4974,15 +4965,14 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat ) { const CSpell * spell = SpellID(spellID).toSpell(); - BattleSpellCastParameters parameters(gs->curB); + BattleSpellCastParameters parameters(gs->curB, attacker, spell); parameters.spellLvl = 0; + parameters.effectLevel = 0; parameters.destination = gs->curB->battleGetStackByID(bat.bsa.at(0).stackAttacked)->position; parameters.casterSide = !attacker->attackerOwned; parameters.casterColor = attacker->owner; - parameters.casterHero = nullptr; parameters.effectPower = power; parameters.mode = ECastingMode::AFTER_ATTACK_CASTING; - parameters.casterStack = attacker; parameters.selectedStack = nullptr; spell->battleCast(this->spellEnv, parameters); @@ -5282,22 +5272,18 @@ void CGameHandler::runBattle() { TBonusListPtr bl = h->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL)); - BattleSpellCastParameters parameters(gs->curB); - parameters.spellLvl = 3; - parameters.destination = BattleHex::INVALID; - parameters.casterSide = i; - parameters.casterColor = h->tempOwner; - parameters.casterHero = h; - parameters.mode = ECastingMode::PASSIVE_CASTING; - parameters.casterStack = nullptr; - parameters.selectedStack = nullptr; - for (Bonus *b : *bl) { - parameters.enchantPower = b->val; - const CSpell * spell = SpellID(b->subtype).toSpell(); - + BattleSpellCastParameters parameters(gs->curB, h, spell); + parameters.spellLvl = 3; + parameters.effectLevel = 3; + parameters.destination = BattleHex::INVALID; + parameters.casterSide = i; + parameters.casterColor = h->tempOwner; + parameters.mode = ECastingMode::PASSIVE_CASTING; + parameters.selectedStack = nullptr; + parameters.enchantPower = b->val; spell->battleCast(spellEnv, parameters); } }