Bladeren bron

Get rid of handleSpellCasting

AlexVinS 11 jaren geleden
bovenliggende
commit
ca5391cde6
4 gewijzigde bestanden met toevoegingen van 176 en 118 verwijderingen
  1. 1 0
      lib/CSpellHandler.h
  2. 35 29
      lib/SpellMechanics.cpp
  3. 137 87
      server/CGameHandler.cpp
  4. 3 2
      server/CGameHandler.h

+ 1 - 0
lib/CSpellHandler.h

@@ -47,6 +47,7 @@ struct SpellSchoolInfo
 class DLL_LINKAGE SpellCastEnvironment
 {
 public:
+	virtual ~SpellCastEnvironment(){};
 	virtual void sendAndApply(CPackForClient * info) const = 0;
 	
 	virtual CRandomGenerator & getRandomGenerator() const = 0;

+ 35 - 29
lib/SpellMechanics.cpp

@@ -230,7 +230,9 @@ public:
 class SacrificeMechanics: public RisingSpellMechanics
 {
 public:
-	SacrificeMechanics(CSpell * s): RisingSpellMechanics(s){};		
+	SacrificeMechanics(CSpell * s): RisingSpellMechanics(s){};	
+protected:
+	void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;		
 };
 
 ///all rising spells but SACRIFICE
@@ -452,7 +454,6 @@ int DefaultSpellMechanics::calculateDuration(const CGHeroInstance * caster, int
 	}	
 }
 
-
 void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
 {
 	//applying effects
@@ -627,33 +628,6 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
 		}
 		if(!shr.healedStacks.empty())
 			env->sendAndApply(&shr);
-		if(owner->id == SpellID::SACRIFICE) //remove victim
-		{
-			if(parameters.selectedStack == parameters.cb->battleActiveStack())
-			//set another active stack than the one removed, or bad things will happen
-			//TODO: make that part of BattleStacksRemoved? what about client update?
-			{
-				//makeStackDoNothing(gs->curB->getStack (selectedStack));
-
-				BattleSetActiveStack sas;
-
-				//std::vector<const CStack *> hlp;
-				//battleGetStackQueue(hlp, 1, selectedStack); //next after this one
-
-				//if(hlp.size())
-				//{
-				//	sas.stack = hlp[0]->ID;
-				//}
-				//else
-				//	complain ("No new stack to activate!");
-				sas.stack = parameters.cb->getNextStack()->ID; //why the hell next stack has same ID as current?
-				env->sendAndApply(&sas);
-
-			}
-			BattleStacksRemoved bsr;
-			bsr.stackIDs.insert(parameters.selectedStack->ID); //somehow it works for teleport?
-			env->sendAndApply(&bsr);
-		}
 	}		
 }
 
@@ -1119,6 +1093,38 @@ void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * en
 		env->complain("There's no obstacle to remove!");	
 }
 
+///SpecialRisingSpellMechanics
+void SacrificeMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
+{
+	RisingSpellMechanics::applyBattleEffects(env, parameters, ctx);
+
+	if(parameters.selectedStack == parameters.cb->battleActiveStack())
+	//set another active stack than the one removed, or bad things will happen
+	//TODO: make that part of BattleStacksRemoved? what about client update?
+	{
+		//makeStackDoNothing(gs->curB->getStack (selectedStack));
+
+		BattleSetActiveStack sas;
+
+		//std::vector<const CStack *> hlp;
+		//battleGetStackQueue(hlp, 1, selectedStack); //next after this one
+
+		//if(hlp.size())
+		//{
+		//	sas.stack = hlp[0]->ID;
+		//}
+		//else
+		//	complain ("No new stack to activate!");
+		sas.stack = parameters.cb->getNextStack()->ID; //why the hell next stack has same ID as current?
+		env->sendAndApply(&sas);
+
+	}
+	BattleStacksRemoved bsr;
+	bsr.stackIDs.insert(parameters.selectedStack->ID); //somehow it works for teleport?
+	env->sendAndApply(&bsr);
+		
+}
+
 
 ///SpecialRisingSpellMechanics
 ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const

+ 137 - 87
server/CGameHandler.cpp

@@ -1064,10 +1064,13 @@ CGameHandler::CGameHandler(void)
 	registerTypesServerPacks(*applier);
 	visitObjectAfterVictory = false;
 	queries.gh = this;
+	
+	spellEnv = new ServerSpellCastEnvironment(this);
 }
 
 CGameHandler::~CGameHandler(void)
 {
+	delete spellEnv;
 	delete applier;
 	applier = nullptr;
 	delete gs;
@@ -3770,17 +3773,27 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 				complain("That stack can't cast spells!");
 			else
 			{
-				int spellLvl = 0;
+				BattleSpellCastParameters p;
+				
+				p.spellLvl = 0;
 				if (spellcaster)
-					vstd::amax(spellLvl, spellcaster->val);
+					vstd::amax(p.spellLvl, spellcaster->val);
 				if (randSpellcaster)
-					vstd::amax(spellLvl, randSpellcaster->val);
-				vstd::amin (spellLvl, 3);
-
-				int casterSide = gs->curB->whatSide(stack->owner);
-				const CGHeroInstance * secHero = gs->curB->getHero(gs->curB->theOtherPlayer(stack->owner));
-
-				handleSpellCasting(spellID, spellLvl, destination, casterSide, stack->owner, nullptr, secHero, 0, ECastingMode::CREATURE_ACTIVE_CASTING, stack);
+					vstd::amax(p.spellLvl, randSpellcaster->val);
+				vstd::amin (p.spellLvl, 3);
+
+				p.casterSide = gs->curB->whatSide(stack->owner);
+				p.secHero = gs->curB->getHero(gs->curB->theOtherPlayer(stack->owner));
+				p.mode = ECastingMode::CREATURE_ACTIVE_CASTING;
+				p.destination = destination;
+				p.casterColor = stack->owner;	
+				p.caster = nullptr;
+				p.usedSpellPower = 0;	
+				p.casterStack = stack;	
+				p.selectedStack = nullptr;				
+
+				const CSpell * spell = SpellID(spellID).toSpell();
+				spell->battleCast(spellEnv, p);
 			}
 			sendAndApply(&end_action);
 			break;
@@ -3944,30 +3957,6 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
 	}
 }
 
-void CGameHandler::handleSpellCasting(SpellID spellID, int spellLvl, BattleHex destination, ui8 casterSide, PlayerColor casterColor, const CGHeroInstance * caster, const CGHeroInstance * secHero,
-	int usedSpellPower, ECastingMode::ECastingMode mode, const CStack * stack, si32 selectedStack)
-{
-	const CSpell * spell = SpellID(spellID).toSpell();
-	
-	ServerSpellCastEnvironment spellEnvironment(this);
-	
-	BattleSpellCastParameters parameters;
-	parameters.spellLvl = spellLvl;
-	parameters.destination = destination;
-	parameters.casterSide = casterSide;
-	parameters.casterColor = casterColor;	
-	parameters.caster = caster;
-	parameters.secHero = secHero;
-	
-	parameters.usedSpellPower = usedSpellPower;	
-	parameters.mode = mode;
-	parameters.casterStack = stack;	
-	parameters.selectedStack = gs->curB->battleGetStackByID(selectedStack, false);
-	
-	
-	spell->battleCast(&spellEnvironment, parameters);
-}
-
 bool CGameHandler::makeCustomAction( BattleAction &ba )
 {
 	switch(ba.actionType)
@@ -3990,52 +3979,49 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 				return false;
 			}
 
-			const CSpell *s = SpellID(ba.additionalInfo).toSpell();
-			if (s->mainEffectAnim > -1
-				|| s->id == SpellID::CLONE
-				|| s->id >= SpellID::SUMMON_FIRE_ELEMENTAL
-				|| s->id <= SpellID::SUMMON_AIR_ELEMENTAL
-				|| s->id <= SpellID::SUMMON_EARTH_ELEMENTAL
-				|| s->id <= SpellID::SUMMON_WATER_ELEMENTAL)
-				//TODO: special effects, like Clone
+			const CSpell * s = SpellID(ba.additionalInfo).toSpell();
+			
+			BattleSpellCastParameters parameters;
+			parameters.spellLvl =  h->getSpellSchoolLevel(s);
+			parameters.destination = ba.destinationTile;
+			parameters.casterSide = ba.side;
+			parameters.casterColor =  h->tempOwner;	
+			parameters.caster = h;
+			parameters.secHero = secondHero;
+			
+			parameters.usedSpellPower = h->getPrimSkillLevel(PrimarySkill::SPELL_POWER);	
+			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);
+			if(escp != ESpellCastProblem::OK)
 			{
-				ui8 skill = h->getSpellSchoolLevel(s); //skill level
-
-				ESpellCastProblem::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h->tempOwner, s, ECastingMode::HERO_CASTING);
-				if(escp != ESpellCastProblem::OK)
-				{
-                    logGlobal->warnStream() << "Spell cannot be cast!";
-                    logGlobal->warnStream() << "Problem : " << escp;
-					return false;
-				}
-
-				StartAction start_action(ba);
-				sendAndApply(&start_action); //start spell casting
-
-				handleSpellCasting (SpellID(ba.additionalInfo), skill, ba.destinationTile, ba.side, h->tempOwner,
-									h, secondHero, h->getPrimSkillLevel(PrimarySkill::SPELL_POWER),
-									ECastingMode::HERO_CASTING, nullptr, ba.selectedStack);
-
-				sendAndApply(&end_action);
-				if( !gs->curB->battleGetStackByID(gs->curB->activeStack, true))
-				{
-					battleMadeAction.setn(true);
-				}
-				checkForBattleEnd();
-				if(battleResult.get())
-				{
-					battleMadeAction.setn(true);
-					//battle will be ended by startBattle function
-					//endBattle(gs->curB->tile, gs->curB->heroes[0], gs->curB->heroes[1]);
-				}
+				logGlobal->warnStream() << "Spell cannot be cast!";
+				logGlobal->warnStream() << "Problem : " << escp;
+				return false;
+			}
 
-				return true;
+			StartAction start_action(ba);
+			sendAndApply(&start_action); //start spell casting
+			
+			s->battleCast(spellEnv, parameters);
+			
+			sendAndApply(&end_action);
+			if( !gs->curB->battleGetStackByID(gs->curB->activeStack, true))
+			{
+				battleMadeAction.setn(true);
 			}
-			else
+			checkForBattleEnd();
+			if(battleResult.get())
 			{
-                logGlobal->warnStream() << "Spell " << s->name << " is not yet supported!";
-				return false;
+				battleMadeAction.setn(true);
+				//battle will be ended by startBattle function
+				//endBattle(gs->curB->tile, gs->curB->heroes[0], gs->curB->heroes[1]);
 			}
+
+			return true;
+
 		}
 	}
 	return false;
@@ -4146,11 +4132,22 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
 		{
 			auto bonus = *RandomGeneratorUtil::nextItem(bl, gs->getRandomGenerator());
 			auto spellID = SpellID(bonus->subtype);
-			if (gs->curB->battleCanCastThisSpell(st->owner, SpellID(spellID).toSpell(), ECastingMode::ENCHANTER_CASTING) == ESpellCastProblem::OK) //TODO: select another available?
+			const CSpell * spell = SpellID(spellID).toSpell();
+			if (gs->curB->battleCanCastThisSpell(st->owner, spell, ECastingMode::ENCHANTER_CASTING) == ESpellCastProblem::OK) //TODO: select another available?
 			{
-				int spellLeveL = bonus->val; //spell level
-				const CGHeroInstance * enemyHero = gs->curB->getHero(gs->curB->theOtherPlayer(st->owner));
-				handleSpellCasting(spellID, spellLeveL, -1, side, st->owner, nullptr, enemyHero, 0, ECastingMode::ENCHANTER_CASTING, st);
+				BattleSpellCastParameters parameters;
+				parameters.spellLvl = bonus->val;
+				parameters.destination = BattleHex::INVALID;
+				parameters.casterSide = side;
+				parameters.casterColor = st->owner;	
+				parameters.caster = nullptr;
+				parameters.secHero = gs->curB->getHero(gs->curB->theOtherPlayer(st->owner));
+				parameters.usedSpellPower = 0;	
+				parameters.mode = ECastingMode::ENCHANTER_CASTING;
+				parameters.casterStack = st;	
+				parameters.selectedStack = nullptr;
+				
+				spell->battleCast(spellEnv, parameters);				
 
 				BattleSetStackProperty ssp;
 				ssp.which = BattleSetStackProperty::ENCHANTER_COUNTER;
@@ -4832,9 +4829,26 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
 			if(gs->getRandomGenerator().nextInt(99) >= chance)
 				continue;
 
-			//casting //TODO: check if spell can be blocked or target is immune
+			//casting
 			if (castMe) //stacks use 0 spell power. If needed, default = 3 or custom value is used
-				handleSpellCasting(spellID, spellLevel, destination, !attacker->attackerOwned, attacker->owner, nullptr, nullptr, 0, ECastingMode::AFTER_ATTACK_CASTING, attacker);
+			{
+				const CSpell * spell = SpellID(spellID).toSpell();
+
+				BattleSpellCastParameters parameters;
+				parameters.spellLvl = spellLevel;
+				parameters.destination = destination;
+				parameters.casterSide = !attacker->attackerOwned;
+				parameters.casterColor = attacker->owner;	
+				parameters.caster = nullptr;
+				parameters.secHero = nullptr;
+
+				parameters.usedSpellPower = 0;	
+				parameters.mode = ECastingMode::AFTER_ATTACK_CASTING;
+				parameters.casterStack = attacker;	
+				parameters.selectedStack = nullptr;
+
+				spell->battleCast(spellEnv, parameters);			
+			}
 		}
 	}
 }
@@ -4850,6 +4864,27 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
 	const CStack * attacker = gs->curB->battleGetStackByID(bat.stackAttacking);
 	if (!attacker) //could be already dead
 		return;
+	
+	auto cast = [=](SpellID spellID, int power)
+	{
+		const CSpell * spell = SpellID(spellID).toSpell();
+
+		BattleSpellCastParameters parameters;
+		parameters.spellLvl = 0;
+		parameters.destination = gs->curB->battleGetStackByID(bat.bsa.at(0).stackAttacked)->position;
+		parameters.casterSide = !attacker->attackerOwned;
+		parameters.casterColor = attacker->owner;	
+		parameters.caster = nullptr;
+		parameters.secHero = nullptr;
+
+		parameters.usedSpellPower = power;	
+		parameters.mode = ECastingMode::AFTER_ATTACK_CASTING;
+		parameters.casterStack = attacker;	
+		parameters.selectedStack = nullptr;
+
+		spell->battleCast(this->spellEnv, parameters);		
+	};	
+	
 	attackCasting(bat, Bonus::SPELL_AFTER_ATTACK, attacker);
 
 	if(bat.bsa.at(0).newAmount <= 0)
@@ -4880,8 +4915,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
 		if (staredCreatures)
 		{
 			if (bat.bsa.at(0).newAmount > 0) //TODO: death stare was not originally available for multiple-hex attacks, but...
-			handleSpellCasting(SpellID::DEATH_STARE, 0, gs->curB->battleGetStackByID(bat.bsa.at(0).stackAttacked)->position,
-				!attacker->attackerOwned, attacker->owner, nullptr, nullptr, staredCreatures, ECastingMode::AFTER_ATTACK_CASTING, attacker);
+				cast(SpellID::DEATH_STARE, staredCreatures);
 		}
 	}
 
@@ -4894,9 +4928,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
 	}
 	if (acidDamage)
 	{
-		handleSpellCasting(SpellID::ACID_BREATH_DAMAGE, 0, gs->curB->battleGetStackByID(bat.bsa.at(0).stackAttacked)->position,
-				!attacker->attackerOwned, attacker->owner, nullptr, nullptr,
-				acidDamage * attacker->count, ECastingMode::AFTER_ATTACK_CASTING, attacker);
+		cast(SpellID::ACID_BREATH_DAMAGE, acidDamage * attacker->count);
 	}
 }
 
@@ -5354,10 +5386,28 @@ void CGameHandler::runBattle()
 		auto h = gs->curB->battleGetFightingHero(i);
 		if(h && h->hasBonusOfType(Bonus::OPENING_BATTLE_SPELL))
 		{
-			TBonusListPtr bl = h->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL));
+			TBonusListPtr bl = h->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL));		
+			
+			BattleSpellCastParameters parameters;
+			parameters.spellLvl = 3;
+			parameters.destination = BattleHex::INVALID;
+			parameters.casterSide = 0;
+			parameters.casterColor = h->tempOwner;	
+			parameters.caster = nullptr;
+			parameters.secHero = gs->curB->battleGetFightingHero(1-i);
+			
+			
+			parameters.mode = ECastingMode::HERO_CASTING;
+			parameters.casterStack = nullptr;	
+			parameters.selectedStack = nullptr;	
+					
 			for (Bonus *b : *bl)
 			{
-				handleSpellCasting(SpellID(b->subtype), 3, -1, 0, h->tempOwner, nullptr, gs->curB->battleGetFightingHero(1-i), b->val, ECastingMode::HERO_CASTING, nullptr);
+				parameters.usedSpellPower = b->val;	
+				
+				const CSpell * spell = SpellID(b->subtype).toSpell();
+				
+				spell->battleCast(spellEnv, parameters);
 			}
 		}
 	}

+ 3 - 2
server/CGameHandler.h

@@ -36,6 +36,8 @@ struct NewStructures;
 class CGHeroInstance;
 class IMarket;
 
+class ServerSpellCastEnvironment;
+
 extern std::map<ui32, CFunctionList<void(ui32)> > callbacks; //question id => callback functions - for selection dialogs
 extern boost::mutex gsm;
 
@@ -201,8 +203,6 @@ public:
 	void playerMessage( PlayerColor player, const std::string &message, ObjectInstanceID currObj);
 	bool makeBattleAction(BattleAction &ba);
 	bool makeAutomaticAction(const CStack *stack, BattleAction &ba); //used when action is taken by stack without volition of player (eg. unguided catapult attack)
-	void handleSpellCasting(SpellID spellID, int spellLvl, BattleHex destination, ui8 casterSide, PlayerColor casterColor, const CGHeroInstance * caster, const CGHeroInstance * secHero,
-		int usedSpellPower, ECastingMode::ECastingMode mode, const CStack * stack, si32 selectedStack = -1);
 	bool makeCustomAction(BattleAction &ba);
 	void stackTurnTrigger(const CStack * stack);
 	void handleDamageFromObstacle(const CObstacleInstance &obstacle, const CStack * curStack); //checks if obstacle is land mine and handles possible consequences
@@ -288,6 +288,7 @@ public:
 	friend class CVCMIServer;
 
 private:
+	ServerSpellCastEnvironment * spellEnv;
 
 	std::list<PlayerColor> generatePlayerTurnOrder() const;
 	void makeStackDoNothing(const CStack * next);