Преглед на файлове

More hero|creature casting unification

AlexVinS преди 10 години
родител
ревизия
2b434111bf

+ 2 - 2
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;

+ 23 - 0
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)

+ 12 - 0
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 <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 1 - 1
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
 }

+ 22 - 0
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
 {

+ 12 - 0
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;

+ 2 - 0
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;

+ 5 - 46
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: "<<owner->name<<"; mode:"<<parameters.mode<<"; level: "<<parameters.spellLvl;
-
-
-	parameters.effectLevel = calculateEffectLevel(parameters);	
+	logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode;
 	
-	if(parameters.casterStack)
-	{
-		if(parameters.enchantPower == 0)
-			parameters.enchantPower = parameters.casterStack->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<std::string> & 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

+ 0 - 2
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;
 	

+ 3 - 1
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"
 

+ 25 - 5
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<const CStack *>(caster);
+	casterHero = dynamic_cast<const CGHeroInstance *>(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):

+ 16 - 13
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

+ 16 - 2
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;
+	
 };

+ 20 - 34
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);
 			}
 		}