Pārlūkot izejas kodu

Moved battle effects into a new class

Ivan Savenko 2 gadi atpakaļ
vecāks
revīzija
cb6fe1eedf

+ 2 - 0
client/CMakeLists.txt

@@ -7,6 +7,7 @@ set(client_SRCS
 		battle/CBattleInterfaceClasses.cpp
 		battle/CBattleInterface.cpp
 		battle/CBattleActionsController.cpp
+		battle/CBattleEffectsController.cpp
 		battle/CBattleFieldController.cpp
 		battle/CBattleObstacleController.cpp
 		battle/CBattleProjectileController.cpp
@@ -84,6 +85,7 @@ set(client_HEADERS
 
 		battle/CBattleAnimations.h
 		battle/CBattleControlPanel.h
+		battle/CBattleEffectsController.h
 		battle/CBattleInterfaceClasses.h
 		battle/CBattleInterface.h
 		battle/CBattleActionsController.h

+ 8 - 9
client/CPlayerInterface.cpp

@@ -13,6 +13,7 @@
 
 #include "windows/CAdvmapInterface.h"
 #include "battle/CBattleInterface.h"
+#include "battle/CBattleEffectsController.h"
 #include "battle/CBattleFieldController.h"
 #include "battle/CBattleInterfaceClasses.h"
 #include "battle/CBattleControlPanel.h"
@@ -768,7 +769,7 @@ void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units
 		}
 	}
 
-	battleInt->displayCustomEffects(customEffects);
+	battleInt->effectsController->displayCustomEffects(customEffects);
 }
 
 void CPlayerInterface::battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles)
@@ -959,7 +960,7 @@ void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte)
 	//TODO why is this different (no return on LOPLINT != this) ?
 
 	RETURN_IF_QUICK_COMBAT;
-	battleInt->battleTriggerEffect(bte);
+	battleInt->effectsController->battleTriggerEffect(bte);
 }
 void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
 {
@@ -974,7 +975,7 @@ void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacke
 		if(elem.isEffect())
 		{
 			if(defender && !elem.isSecondary())
-				battleInt->displayEffect(elem.effect, defender->getPosition());
+				battleInt->effectsController->displayEffect(EBattleEffect::EBattleEffect(elem.effect), defender->getPosition());
 		}
 		if(elem.isSpell())
 		{
@@ -1010,14 +1011,12 @@ void CPlayerInterface::battleAttack(const BattleAttack * ba)
 	if(ba->lucky()) //lucky hit
 	{
 		battleInt->controlPanel->console->addText(attacker->formatGeneralMessage(-45));
-		battleInt->displayEffect(18, attacker->getPosition());
-		CCS->soundh->playSound(soundBase::GOODLUCK);
+		battleInt->effectsController->displayEffect(EBattleEffect::GOOD_LUCK, soundBase::GOODLUCK, attacker->getPosition());
 	}
 	if(ba->unlucky()) //unlucky hit
 	{
 		battleInt->controlPanel->console->addText(attacker->formatGeneralMessage(-44));
-		battleInt->displayEffect(48, attacker->getPosition());
-		CCS->soundh->playSound(soundBase::BADLUCK);
+		battleInt->effectsController->displayEffect(EBattleEffect::BAD_LUCK, soundBase::BADLUCK, attacker->getPosition());
 	}
 	if(ba->deathBlow())
 	{
@@ -1025,12 +1024,12 @@ void CPlayerInterface::battleAttack(const BattleAttack * ba)
 		for(auto & elem : ba->bsa)
 		{
 			const CStack * attacked = cb->battleGetStackByID(elem.stackAttacked);
-			battleInt->displayEffect(73, attacked->getPosition());
+			battleInt->effectsController->displayEffect(EBattleEffect::DEATH_BLOW, attacked->getPosition());
 		}
 		CCS->soundh->playSound(soundBase::deathBlow);
 	}
 
-	battleInt->displayCustomEffects(ba->customEffects);
+	battleInt->effectsController->displayCustomEffects(ba->customEffects);
 
 	battleInt->waitForAnims();
 

+ 11 - 20
client/battle/CBattleAnimations.cpp

@@ -17,6 +17,7 @@
 #include "CBattleProjectileController.h"
 #include "CBattleSiegeController.h"
 #include "CBattleFieldController.h"
+#include "CBattleEffectsController.h"
 #include "CBattleStacksController.h"
 #include "CCreatureAnimation.h"
 
@@ -184,9 +185,6 @@ killed(_attackedInfo.killed), timeToWait(0)
 
 bool CDefenceAnimation::init()
 {
-	if(attacker == nullptr && owner->battleEffects.size() > 0)
-		return false;
-
 	ui32 lowestMoveID = maxAnimationID() + 5;
 	for(auto & elem : pendingAnimations())
 	{
@@ -200,6 +198,9 @@ bool CDefenceAnimation::init()
 			continue;
 
 		CEffectAnimation * sen = dynamic_cast<CEffectAnimation *>(elem.first);
+		if (sen && attacker == nullptr)
+			return false;
+
 		if (sen)
 			continue;
 
@@ -1078,7 +1079,7 @@ bool CEffectAnimation::init()
 				be.y = j * first->height() + owner->pos.y;
 				be.position = BattleHex::INVALID;
 
-				owner->battleEffects.push_back(be);
+				owner->effectsController->battleEffects.push_back(be);
 			}
 		}
 	}
@@ -1121,16 +1122,15 @@ bool CEffectAnimation::init()
 		//Indicate if effect should be drawn on top of everything or just on top of the hex
 		be.position = destTile;
 
-		owner->battleEffects.push_back(be);
+		owner->effectsController->battleEffects.push_back(be);
 	}
-	//battleEffects
 	return true;
 }
 
 void CEffectAnimation::nextFrame()
 {
 	//notice: there may be more than one effect in owner->battleEffects correcponding to this animation (ie. armageddon)
-	for(auto & elem : owner->battleEffects)
+	for(auto & elem : owner->effectsController->battleEffects)
 	{
 		if(elem.effectID == ID)
 		{
@@ -1154,20 +1154,11 @@ void CEffectAnimation::endAnim()
 {
 	CBattleAnimation::endAnim();
 
-	std::vector<std::list<BattleEffect>::iterator> toDel;
-
-	for(auto it = owner->battleEffects.begin(); it != owner->battleEffects.end(); ++it)
-	{
-		if(it->effectID == ID)
+	boost::range::remove_if(owner->effectsController->battleEffects,
+		[&](const BattleEffect & elem)
 		{
-			toDel.push_back(it);
-		}
-	}
-
-	for(auto & elem : toDel)
-	{
-		owner->battleEffects.erase(elem);
-	}
+			return elem.effectID == ID;
+		});
 
 	delete this;
 }

+ 1 - 0
client/battle/CBattleControlPanel.cpp

@@ -14,6 +14,7 @@
 #include "CBattleStacksController.h"
 #include "CBattleActionsController.h"
 #include "../widgets/Buttons.h"
+#include "../widgets/Images.h"
 #include "../CGameInfo.h"
 #include "../CBitmapHandler.h"
 #include "../../lib/CGeneralTextHandler.h"

+ 152 - 0
client/battle/CBattleEffectsController.cpp

@@ -0,0 +1,152 @@
+/*
+ * CBattleEffectsController.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 "CBattleEffectsController.h"
+
+#include "CBattleAnimations.h"
+#include "CBattleControlPanel.h"
+#include "CBattleInterface.h"
+#include "CBattleInterfaceClasses.h"
+#include "CBattleStacksController.h"
+#include "../gui/CAnimation.h"
+#include "../CMusicHandler.h"
+#include "../CGameInfo.h"
+#include "../CPlayerInterface.h"
+#include "../../CCallback.h"
+#include "../../lib/battle/BattleAction.h"
+#include "../../lib/NetPacks.h"
+#include "../../lib/CStack.h"
+#include "../../lib/IGameEventsReceiver.h"
+#include "../../lib/CGeneralTextHandler.h"
+
+CBattleEffectsController::CBattleEffectsController(CBattleInterface * owner):
+	owner(owner)
+{}
+
+void CBattleEffectsController::displayEffect(EBattleEffect::EBattleEffect effect, const BattleHex & destTile)
+{
+	std::string customAnim = graphics->battleACToDef[effect][0];
+
+	owner->stacksController->addNewAnim(new CEffectAnimation(owner, customAnim, destTile));
+}
+
+void CBattleEffectsController::displayEffect(EBattleEffect::EBattleEffect effect, uint32_t soundID, const BattleHex & destTile)
+{
+	displayEffect(effect, destTile);
+	if(soundBase::soundID(soundID) != soundBase::invalid )
+		CCS->soundh->playSound(soundBase::soundID(soundID));
+}
+
+void CBattleEffectsController::displayCustomEffects(const std::vector<CustomEffectInfo> & customEffects)
+{
+	for(const CustomEffectInfo & one : customEffects)
+	{
+		if(one.sound != 0)
+			CCS->soundh->playSound(soundBase::soundID(one.sound));
+		const CStack * s = owner->curInt->cb->battleGetStackByID(one.stack, false);
+		if(s && one.effect != 0)
+			displayEffect(EBattleEffect::EBattleEffect(one.effect), s->getPosition());
+	}
+}
+
+void CBattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bte)
+{
+	const CStack * stack = owner->curInt->cb->battleGetStackByID(bte.stackID);
+	if(!stack)
+	{
+		logGlobal->error("Invalid stack ID %d", bte.stackID);
+		return;
+	}
+	//don't show animation when no HP is regenerated
+	switch(bte.effect)
+	{
+		//TODO: move to bonus type handler
+		case Bonus::HP_REGENERATION:
+			displayEffect(EBattleEffect::REGENERATION, soundBase::REGENER, stack->getPosition());
+			break;
+		case Bonus::MANA_DRAIN:
+			displayEffect(EBattleEffect::MANA_DRAIN, soundBase::MANADRAI, stack->getPosition());
+			break;
+		case Bonus::POISON:
+			displayEffect(EBattleEffect::POISON, soundBase::POISON, stack->getPosition());
+			break;
+		case Bonus::FEAR:
+			displayEffect(EBattleEffect::FEAR, soundBase::FEAR, stack->getPosition());
+			break;
+		case Bonus::MORALE:
+		{
+			std::string hlp = CGI->generaltexth->allTexts[33];
+			boost::algorithm::replace_first(hlp,"%s",(stack->getName()));
+			displayEffect(EBattleEffect::GOOD_MORALE, soundBase::GOODMRLE, stack->getPosition());
+			owner->controlPanel->console->addText(hlp);
+			break;
+		}
+		default:
+			return;
+	}
+	//waitForAnims(); //fixme: freezes game :?
+}
+
+
+void CBattleEffectsController::startAction(const BattleAction* action)
+{
+	const CStack *stack = owner->curInt->cb->battleGetStackByID(action->stackNumber);
+
+	int txtid = 0;
+	switch(action->actionType)
+	{
+	case EActionType::WAIT:
+		txtid = 136;
+		break;
+	case EActionType::BAD_MORALE:
+		txtid = -34; //negative -> no separate singular/plural form
+		displayEffect(EBattleEffect::BAD_MORALE, soundBase::BADMRLE, stack->getPosition());
+		break;
+	}
+
+	if(txtid != 0)
+		owner->controlPanel->console->addText(stack->formatGeneralMessage(txtid));
+
+	//displaying special abilities
+	auto actionTarget = action->getTarget(owner->curInt->cb.get());
+	switch(action->actionType)
+	{
+		case EActionType::STACK_HEAL:
+			displayEffect(EBattleEffect::REGENERATION, soundBase::REGENER, actionTarget.at(0).hexValue);
+			break;
+	}
+}
+
+
+void CBattleEffectsController::showBattleEffects(SDL_Surface *to, const std::vector<const BattleEffect *> &battleEffects)
+{
+	for (auto & elem : battleEffects)
+	{
+		int currentFrame = static_cast<int>(floor(elem->currentFrame));
+		currentFrame %= elem->animation->size();
+
+		auto img = elem->animation->getImage(currentFrame);
+
+		SDL_Rect temp_rect = genRect(img->height(), img->width(), elem->x, elem->y);
+
+		img->draw(to, &temp_rect, nullptr);
+	}
+}
+
+void CBattleEffectsController::sortObjectsByHex(BattleObjectsByHex & sorted)
+{
+	for (auto & battleEffect : battleEffects)
+	{
+		if (battleEffect.position.isValid())
+			sorted.hex[battleEffect.position].effects.push_back(&battleEffect);
+		else
+			sorted.afterAll.effects.push_back(&battleEffect);
+	}
+}

+ 73 - 0
client/battle/CBattleEffectsController.h

@@ -0,0 +1,73 @@
+/*
+ * CBattleEffectsController.h, 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
+ *
+ */
+#pragma once
+
+#include "../../lib/battle/BattleHex.h"
+
+struct SDL_Surface;
+class BattleAction;
+class CAnimation;
+class CBattleInterface;
+struct BattleObjectsByHex;
+struct CustomEffectInfo;
+struct BattleTriggerEffect;
+class CEffectAnimation;
+
+namespace EBattleEffect
+{
+	enum EBattleEffect
+	{
+		// list of battle effects that have hardcoded triggers
+		FEAR         = 15,
+		GOOD_LUCK    = 18,
+		GOOD_MORALE  = 20,
+		BAD_MORALE   = 30,
+		BAD_LUCK     = 48,
+		RESURRECT    = 50,
+		POISON       = 67,
+		DEATH_BLOW   = 73,
+		REGENERATION = 74,
+		MANA_DRAIN   = 77,
+
+		INVALID      = -1,
+	};
+}
+
+/// Struct for battle effect animation e.g. morale, prayer, armageddon, bless,...
+struct BattleEffect
+{
+	int x, y; //position on the screen
+	float currentFrame;
+	std::shared_ptr<CAnimation> animation;
+	int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim
+	BattleHex position; //Indicates if effect which hex the effect is drawn on
+};
+
+class CBattleEffectsController
+{
+	CBattleInterface * owner;
+
+	std::vector<BattleEffect> battleEffects; //different animations to display on the screen like spell effects
+public:
+	CBattleEffectsController(CBattleInterface * owner);
+
+	void startAction(const BattleAction* action);
+	void sortObjectsByHex(BattleObjectsByHex & sorted);
+
+	void displayCustomEffects(const std::vector<CustomEffectInfo> & customEffects);
+
+	void displayEffect(EBattleEffect::EBattleEffect effect, const BattleHex & destTile); //displays custom effect on the battlefield
+	void displayEffect(EBattleEffect::EBattleEffect effect, uint32_t soundID, const BattleHex & destTile); //displays custom effect on the battlefield
+	void battleTriggerEffect(const BattleTriggerEffect & bte);
+	void showBattleEffects(SDL_Surface *to, const std::vector<const BattleEffect *> &battleEffects);
+
+
+	friend class CEffectAnimation; // currently, battleEffects is largely managed by CEffectAnimation, TODO: move this logic into CBattleEffectsController
+};

+ 5 - 119
client/battle/CBattleInterface.cpp

@@ -15,6 +15,7 @@
 #include "CBattleInterfaceClasses.h"
 #include "CCreatureAnimation.h"
 #include "CBattleProjectileController.h"
+#include "CBattleEffectsController.h"
 #include "CBattleObstacleController.h"
 #include "CBattleSiegeController.h"
 #include "CBattleFieldController.h"
@@ -583,7 +584,7 @@ void CBattleInterface::spellCast(const BattleSpellCast * sc)
 	{
 		auto stack = curInt->cb->battleGetStackByID(elem.stack, false);
 		if(stack)
-			displayEffect(elem.effect, stack->getPosition());
+			effectsController->displayEffect(EBattleEffect::EBattleEffect(elem.effect), stack->getPosition());
 	}
 
 	waitForAnims();
@@ -628,25 +629,6 @@ void CBattleInterface::displayBattleLog(const std::vector<MetaString> & battleLo
 	}
 }
 
-void CBattleInterface::displayCustomEffects(const std::vector<CustomEffectInfo> & customEffects)
-{
-	for(const CustomEffectInfo & one : customEffects)
-	{
-		if(one.sound != 0)
-			CCS->soundh->playSound(soundBase::soundID(one.sound));
-		const CStack * s = curInt->cb->battleGetStackByID(one.stack, false);
-		if(s && one.effect != 0)
-			displayEffect(one.effect, s->getPosition());
-	}
-}
-
-void CBattleInterface::displayEffect(ui32 effect, BattleHex destTile)
-{
-	std::string customAnim = graphics->battleACToDef[effect][0];
-
-	stacksController->addNewAnim(new CEffectAnimation(this, customAnim, destTile));
-}
-
 void CBattleInterface::displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile)
 {
 	for(const CSpell::TAnimation & animation : q)
@@ -682,49 +664,6 @@ void CBattleInterface::displaySpellHit(SpellID spellID, BattleHex destinationTil
 		displaySpellAnimationQueue(spell->animationInfo.hit, destinationTile);
 }
 
-void CBattleInterface::battleTriggerEffect(const BattleTriggerEffect & bte)
-{
-	const CStack * stack = curInt->cb->battleGetStackByID(bte.stackID);
-	if(!stack)
-	{
-		logGlobal->error("Invalid stack ID %d", bte.stackID);
-		return;
-	}
-	//don't show animation when no HP is regenerated
-	switch(bte.effect)
-	{
-		//TODO: move to bonus type handler
-		case Bonus::HP_REGENERATION:
-			displayEffect(74, stack->getPosition());
-			CCS->soundh->playSound(soundBase::REGENER);
-			break;
-		case Bonus::MANA_DRAIN:
-			displayEffect(77, stack->getPosition());
-			CCS->soundh->playSound(soundBase::MANADRAI);
-			break;
-		case Bonus::POISON:
-			displayEffect(67, stack->getPosition());
-			CCS->soundh->playSound(soundBase::POISON);
-			break;
-		case Bonus::FEAR:
-			displayEffect(15, stack->getPosition());
-			CCS->soundh->playSound(soundBase::FEAR);
-			break;
-		case Bonus::MORALE:
-		{
-			std::string hlp = CGI->generaltexth->allTexts[33];
-			boost::algorithm::replace_first(hlp,"%s",(stack->getName()));
-			displayEffect(20,stack->getPosition());
-			CCS->soundh->playSound(soundBase::GOODMRLE);
-			controlPanel->console->addText(hlp);
-			break;
-		}
-		default:
-			return;
-	}
-	//waitForAnims(); //fixme: freezes game :?
-}
-
 void CBattleInterface::setAnimSpeed(int set)
 {
 	Settings speed = settings.write["battle"]["animationSpeed"];
@@ -830,7 +769,6 @@ void CBattleInterface::showQueue()
 
 void CBattleInterface::startAction(const BattleAction* action)
 {
-	//setActiveStack(nullptr);
 	controlPanel->blockUI(true);
 
 	if(action->actionType == EActionType::END_TACTIC_PHASE)
@@ -866,31 +804,7 @@ void CBattleInterface::startAction(const BattleAction* action)
 		return;
 	}
 
-	int txtid = 0;
-	switch(action->actionType)
-	{
-	case EActionType::WAIT:
-		txtid = 136;
-		break;
-	case EActionType::BAD_MORALE:
-		txtid = -34; //negative -> no separate singular/plural form
-		displayEffect(30, stack->getPosition());
-		CCS->soundh->playSound(soundBase::BADMRLE);
-		break;
-	}
-
-	if(txtid != 0)
-		controlPanel->console->addText(stack->formatGeneralMessage(txtid));
-
-	//displaying special abilities
-	auto actionTarget = action->getTarget(curInt->cb.get());
-	switch(action->actionType)
-	{
-		case EActionType::STACK_HEAL:
-			displayEffect(74, actionTarget.at(0).hexValue);
-			CCS->soundh->playSound(soundBase::REGENER);
-			break;
-	}
+	effectsController->startAction(action);
 }
 
 void CBattleInterface::waitForAnims()
@@ -1051,7 +965,7 @@ void CBattleInterface::showBattlefieldObjects(SDL_Surface *to)
 			siegeController->showPiecesOfWall(to, hex.walls);
 		obstacleController->showObstacles(to, hex.obstacles);
 		stacksController->showAliveStacks(to, hex.alive);
-		showBattleEffects(to, hex.effects);
+		effectsController->showBattleEffects(to, hex.effects);
 	};
 
 	BattleObjectsByHex objects = sortObjectsByHex();
@@ -1080,21 +994,6 @@ void CBattleInterface::showBattlefieldObjects(SDL_Surface *to)
 	showHexEntry(objects.afterAll);
 }
 
-void CBattleInterface::showBattleEffects(SDL_Surface *to, const std::vector<const BattleEffect *> &battleEffects)
-{
-	for (auto & elem : battleEffects)
-	{
-		int currentFrame = static_cast<int>(floor(elem->currentFrame));
-		currentFrame %= elem->animation->size();
-
-		auto img = elem->animation->getImage(currentFrame);
-
-		SDL_Rect temp_rect = genRect(img->height(), img->width(), elem->x, elem->y);
-
-		img->draw(to, &temp_rect, nullptr);
-	}
-}
-
 void CBattleInterface::showInterface(SDL_Surface *to)
 {
 	//showing in-game console
@@ -1125,22 +1024,9 @@ BattleObjectsByHex CBattleInterface::sortObjectsByHex()
 {
 	BattleObjectsByHex sorted;
 
-	// Sort creatures
 	stacksController->sortObjectsByHex(sorted);
-
-	// Sort battle effects (spells)
-	for (auto & battleEffect : battleEffects)
-	{
-		if (battleEffect.position.isValid())
-			sorted.hex[battleEffect.position].effects.push_back(&battleEffect);
-		else
-			sorted.afterAll.effects.push_back(&battleEffect);
-	}
-
-	// Sort obstacles
 	obstacleController->sortObjectsByHex(sorted);
-
-	// Sort wall parts
+	effectsController->sortObjectsByHex(sorted);
 	if (siegeController)
 		siegeController->sortObjectsByHex(sorted);
 

+ 13 - 40
client/battle/CBattleInterface.h

@@ -9,16 +9,8 @@
  */
 #pragma once
 
-#include <vcmi/spells/Magic.h>
-
-#include "../../lib/ConstTransitivePtr.h" //may be redundant
-#include "../../lib/GameConstants.h"
-
-#include "CBattleAnimations.h"
-
+#include "../gui/CIntObject.h"
 #include "../../lib/spells/CSpellHandler.h" //CSpell::TAnimation
-#include "../../lib/CCreatureHandler.h"
-#include "../../lib/battle/CBattleInfoCallback.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -36,27 +28,25 @@ struct CatapultAttack;
 struct BattleTriggerEffect;
 struct BattleHex;
 struct InfoAboutHero;
-class CBattleGameInterface;
+//class CBattleGameInterface;
 struct CustomEffectInfo;
-class CSpell;
+//class CSpell;
 
 VCMI_LIB_NAMESPACE_END
 
-class CLabel;
-class CCallback;
-class CButton;
-class CToggleButton;
-class CToggleGroup;
-class CBattleAnimation;
+//class CLabel;
+//class CCallback;
+//class CBattleAnimation;
 class CBattleHero;
-class CBattleConsole;
+//class CBattleConsole;
 class CBattleResultWindow;
 class CStackQueue;
 class CPlayerInterface;
-class CCreatureAnimation;
+//class CCreatureAnimation;
 class CClickableHex;
 class CAnimation;
-class IImage;
+//class IImage;
+struct BattleEffect;
 
 class CBattleProjectileController;
 class CBattleSiegeController;
@@ -65,6 +55,7 @@ class CBattleFieldController;
 class CBattleControlPanel;
 class CBattleStacksController;
 class CBattleActionsController;
+class CBattleEffectsController;
 
 /// Small struct which contains information about the id of the attacked stack, the damage dealt,...
 struct StackAttackedInfo
@@ -79,15 +70,6 @@ struct StackAttackedInfo
 	bool cloneKilled;
 };
 
-/// Struct for battle effect animation e.g. morale, prayer, armageddon, bless,...
-struct BattleEffect
-{
-	int x, y; //position on the screen
-	float currentFrame;
-	std::shared_ptr<CAnimation> animation;
-	int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim
-	BattleHex position; //Indicates if effect which hex the effect is drawn on
-};
 
 struct BattleObjectsByHex
 {
@@ -133,8 +115,6 @@ private:
 	bool battleActionsStarted; //used for delaying battle actions until intro sound stops
 	int battleIntroSoundChannel; //required as variable for disabling it via ESC key
 
-	std::list<BattleEffect> battleEffects; //different animations to display on the screen like spell effects
-
 	void trySetActivePlayer( PlayerColor player ); // if in hotseat, will activate interface of chosen player
 	void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
 	void requestAutofightingAIToTakeAction();
@@ -149,8 +129,6 @@ private:
 
 	void showBattlefieldObjects(SDL_Surface *to);
 
-	void showBattleEffects(SDL_Surface *to, const std::vector<const BattleEffect *> &battleEffects);
-
 	BattleObjectsByHex sortObjectsByHex();
 
 	void setHeroAnimation(ui8 side, int phase);
@@ -161,6 +139,7 @@ public:
 	std::unique_ptr<CBattleFieldController> fieldController;
 	std::unique_ptr<CBattleStacksController> stacksController;
 	std::unique_ptr<CBattleActionsController> actionsController;
+	std::unique_ptr<CBattleEffectsController> effectsController;
 
 	static CondSh<bool> animsAreDisplayed; //for waiting with the end of battle for end of anims
 	static CondSh<BattleAction *> givenCommand; //data != nullptr if we have i.e. moved current unit
@@ -174,7 +153,6 @@ public:
 	CBattleInterface(const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, const SDL_Rect & myRect, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen, std::shared_ptr<CPlayerInterface> spectatorInt = nullptr);
 	virtual ~CBattleInterface();
 
-	//std::vector<TimeInterested*> timeinterested; //animation handling
 	void setPrintCellBorders(bool set); //if true, cell borders will be printed
 	void setPrintStackRange(bool set); //if true,range of active stack will be printed
 	void setPrintMouseShadow(bool set); //if true, hex under mouse will be shaded
@@ -216,16 +194,12 @@ public:
 	void castThisSpell(SpellID spellID); //called when player has chosen a spell from spellbook
 
 	void displayBattleLog(const std::vector<MetaString> & battleLog);
-	void displayCustomEffects(const std::vector<CustomEffectInfo> & customEffects);
-
-	void displayEffect(ui32 effect, BattleHex destTile); //displays custom effect on the battlefield
 
 	void displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile);
 	void displaySpellCast(SpellID spellID, BattleHex destinationTile); //displays spell`s cast animation
 	void displaySpellEffect(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation
 	void displaySpellHit(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation
 
-	void battleTriggerEffect(const BattleTriggerEffect & bte);
 	void endAction(const BattleAction* action);
 	void hideQueue();
 	void showQueue();
@@ -234,12 +208,10 @@ public:
 
 	void gateStateChanged(const EGateState state);
 
-
 	const CGHeroInstance *currentHero() const;
 	InfoAboutHero enemyHero() const;
 
 	friend class CPlayerInterface;
-	friend class CButton;
 	friend class CInGameConsole;
 
 	friend class CBattleResultWindow;
@@ -262,4 +234,5 @@ public:
 	friend class CBattleControlPanel;
 	friend class CBattleStacksController;
 	friend class CBattleActionsController;
+	friend class CBattleEffectsController;
 };

+ 1 - 0
client/battle/CBattleInterfaceClasses.cpp

@@ -29,6 +29,7 @@
 #include "../gui/CGuiHandler.h"
 #include "../gui/SDL_Extensions.h"
 #include "../widgets/Buttons.h"
+#include "../widgets/Images.h"
 #include "../widgets/TextControls.h"
 #include "../windows/CCreatureWindow.h"
 #include "../windows/CSpellWindow.h"

+ 1 - 0
client/battle/CBattleObstacleController.cpp

@@ -11,6 +11,7 @@
 #include "CBattleObstacleController.h"
 #include "CBattleInterface.h"
 #include "CBattleFieldController.h"
+#include "CBattleAnimations.h"
 #include "CBattleStacksController.h"
 #include "../CPlayerInterface.h"
 #include "../../CCallback.h"

+ 3 - 2
client/battle/CBattleStacksController.cpp

@@ -12,7 +12,9 @@
 #include "CBattleSiegeController.h"
 #include "CBattleInterfaceClasses.h"
 #include "CBattleInterface.h"
+#include "CBattleAnimations.h"
 #include "CBattleFieldController.h"
+#include "CBattleEffectsController.h"
 #include "CBattleProjectileController.h"
 #include "CBattleControlPanel.h"
 #include "../CBitmapHandler.h"
@@ -444,8 +446,7 @@ void CBattleStacksController::stacksAreAttacked(std::vector<StackAttackedInfo> a
 
 		if(attackedInfo.rebirth)
 		{
-			owner->displayEffect(50, attackedInfo.defender->getPosition()); //TODO: play reverse death animation
-			CCS->soundh->playSound(soundBase::RESURECT);
+			owner->effectsController->displayEffect(EBattleEffect::RESURRECT, soundBase::RESURECT, attackedInfo.defender->getPosition()); //TODO: play reverse death animation
 		}
 	}
 	owner->waitForAnims();

+ 1 - 0
client/windows/CWindowObject.cpp

@@ -13,6 +13,7 @@
 #include "CAdvmapInterface.h"
 
 #include "../widgets/MiscWidgets.h"
+#include "../widgets/Images.h"
 
 #include "../gui/SDL_Pixels.h"
 #include "../gui/SDL_Extensions.h"