Browse Source

Fixes to effects of earthquake, obstacle-creating and offensive spells

Ivan Savenko 2 years ago
parent
commit
58ba5f1aee

+ 56 - 31
client/battle/CBattleAnimations.cpp

@@ -980,17 +980,17 @@ CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBas
 {
 }
 
-CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> pos, int effects):
+CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> hex, int effects):
 	CPointEffectAnimation(_owner, sound, animationName, effects)
 {
-	battlehexes = pos;
+	battlehexes = hex;
 }
 
-CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex pos, int effects):
+CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex hex, int effects):
 	CPointEffectAnimation(_owner, sound, animationName, effects)
 {
-	assert(pos.isValid());
-	battlehexes.push_back(pos);
+	assert(hex.isValid());
+	battlehexes.push_back(hex);
 }
 
 CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<Point> pos, int effects):
@@ -1005,6 +1005,14 @@ CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBas
 	positions.push_back(pos);
 }
 
+CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, Point pos, BattleHex hex,   int effects):
+	CPointEffectAnimation(_owner, sound, animationName, effects)
+{
+	assert(hex.isValid());
+	battlehexes.push_back(hex);
+	positions.push_back(pos);
+}
+
 bool CPointEffectAnimation::init()
 {
 	if(!CBattleAnimation::checkInitialConditions())
@@ -1019,9 +1027,8 @@ bool CPointEffectAnimation::init()
 		return false;
 	}
 
-	if (positions.empty() && battlehexes.empty())
+	if (screenFill())
 	{
-		//armageddon, create screen fill
 		for(int i=0; i * first->width() < owner->pos.w ; ++i)
 			for(int j=0; j * first->height() < owner->pos.h ; ++j)
 				positions.push_back(Point(i * first->width(), j * first->height()));
@@ -1032,35 +1039,36 @@ bool CPointEffectAnimation::init()
 	be.animation = animation;
 	be.currentFrame = 0;
 
-	for ( auto const position : positions)
-	{
-		be.x = position.x;
-		be.y = position.y;
-		be.position = BattleHex::INVALID;
-
-		owner->effectsController->battleEffects.push_back(be);
-	}
-
-	for ( auto const tile : battlehexes)
+	for (size_t i = 0; i < std::max(battlehexes.size(), positions.size()); ++i)
 	{
-		const CStack * destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(tile, false);
+		bool hasTile = i < battlehexes.size();
+		bool hasPosition = i < positions.size();
 
-		assert(tile.isValid());
-		if(!tile.isValid())
-			continue;
+		if (hasTile && !forceOnTop())
+			be.position = battlehexes[i];
+		else
+			be.position = BattleHex::INVALID;
 
-		Rect tilePos = owner->fieldController->hexPosition(tile);
-		be.position = tile;
-		be.x = tilePos.x + tilePos.w/2 - first->width()/2;
+		if (hasPosition)
+		{
+			be.x = positions[i].x;
+			be.y = positions[i].y;
+		}
+		else
+		{
+			const CStack * destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(battlehexes[i], false);
+			Rect tilePos = owner->fieldController->hexPosition(battlehexes[i]);
 
-		if(destStack && destStack->doubleWide()) // Correction for 2-hex creatures.
-			be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2;
+			be.x = tilePos.x + tilePos.w/2 - first->width()/2;
 
-		if (alignToBottom())
-			be.y = tilePos.y + tilePos.h - first->height();
-		else
-			be.y = tilePos.y - first->height()/2;
+			if(destStack && destStack->doubleWide()) // Correction for 2-hex creatures.
+				be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2;
 
+			if (alignToBottom())
+				be.y = tilePos.y + tilePos.h - first->height();
+			else
+				be.y = tilePos.y - first->height()/2;
+		}
 		owner->effectsController->battleEffects.push_back(be);
 	}
 	return true;
@@ -1072,7 +1080,11 @@ void CPointEffectAnimation::nextFrame()
 	playEffect();
 
 	if (soundFinished && effectFinished)
+	{
+		//remove visual effect itself only if sound has finished as well - necessary for obstacles like force field
+		clearEffect();
 		delete this;
+	}
 }
 
 bool CPointEffectAnimation::alignToBottom() const
@@ -1085,10 +1097,19 @@ bool CPointEffectAnimation::waitForSound() const
 	return effectFlags & WAIT_FOR_SOUND;
 }
 
+bool CPointEffectAnimation::forceOnTop() const
+{
+	return effectFlags & FORCE_ON_TOP;
+}
+
+bool CPointEffectAnimation::screenFill() const
+{
+	return effectFlags & SCREEN_FILL;
+}
+
 void CPointEffectAnimation::onEffectFinished()
 {
 	effectFinished = true;
-	clearEffect();
 }
 
 void CPointEffectAnimation::onSoundFinished()
@@ -1118,6 +1139,9 @@ void CPointEffectAnimation::playSound()
 
 void CPointEffectAnimation::playEffect()
 {
+	if ( effectFinished )
+		return;
+
 	for(auto & elem : owner->effectsController->battleEffects)
 	{
 		if(elem.effectID == ID)
@@ -1126,6 +1150,7 @@ void CPointEffectAnimation::playEffect()
 
 			if(elem.currentFrame >= elem.animation->size())
 			{
+				elem.currentFrame = elem.animation->size() - 1;
 				onEffectFinished();
 				break;
 			}

+ 22 - 3
client/battle/CBattleAnimations.h

@@ -262,6 +262,19 @@ public:
 	CCastAnimation(CBattleInterface * owner_, const CStack * attacker, BattleHex dest_, const CStack * defender, const CSpell * spell);
 };
 
+struct CPointEffectParameters
+{
+	std::vector<Point> positions;
+	std::vector<BattleHex> tiles;
+	std::string animation;
+
+	soundBase::soundID sound = soundBase::invalid;
+	BattleHex boundHex = BattleHex::INVALID;
+	bool aligntoBottom = false;
+	bool waitForSound = false;
+	bool screenFill = false;
+};
+
 /// Class that plays effect at one or more positions along with (single) sound effect
 class CPointEffectAnimation : public CBattleAnimation
 {
@@ -277,6 +290,8 @@ class CPointEffectAnimation : public CBattleAnimation
 
 	bool alignToBottom() const;
 	bool waitForSound() const;
+	bool forceOnTop() const;
+	bool screenFill() const;
 
 	void onEffectFinished();
 	void onSoundFinished();
@@ -289,7 +304,9 @@ public:
 	enum EEffectFlags
 	{
 		ALIGN_TO_BOTTOM = 1,
-		WAIT_FOR_SOUND  = 2
+		WAIT_FOR_SOUND  = 2,
+		FORCE_ON_TOP    = 4,
+		SCREEN_FILL     = 8,
 	};
 
 	/// Create animation with screen-wide effect
@@ -300,8 +317,10 @@ public:
 	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<Point> pos    , int effects = 0);
 
 	/// Create animation positioned at certain hex(es)
-	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex pos             , int effects = 0);
-	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> pos, int effects = 0);
+	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex hex             , int effects = 0);
+	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> hex, int effects = 0);
+
+	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, Point pos, BattleHex hex,   int effects = 0);
 	 ~CPointEffectAnimation();
 
 	bool init() override;

+ 17 - 8
client/battle/CBattleInterface.cpp

@@ -583,7 +583,7 @@ void CBattleInterface::displayBattleLog(const std::vector<MetaString> & battleLo
 	}
 }
 
-void CBattleInterface::displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile)
+void CBattleInterface::displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile, bool isHit)
 {
 	for(const CSpell::TAnimation & animation : q)
 	{
@@ -591,12 +591,21 @@ void CBattleInterface::displaySpellAnimationQueue(const CSpell::TAnimationQueue
 			stacksController->addNewAnim(new CDummyAnimation(this, animation.pause));
 		else
 		{
+			int flags = 0;
+
+			if (isHit)
+				flags |= CPointEffectAnimation::FORCE_ON_TOP;
+
+			if (animation.verticalPosition == VerticalPosition::BOTTOM)
+				flags |= CPointEffectAnimation::ALIGN_TO_BOTTOM;
+
+			if (!destinationTile.isValid())
+				flags |= CPointEffectAnimation::SCREEN_FILL;
+
 			if (!destinationTile.isValid())
-				stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName));
-			else if (animation.verticalPosition == VerticalPosition::BOTTOM)
-				stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, destinationTile, CPointEffectAnimation::ALIGN_TO_BOTTOM));
+				stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, flags));
 			else
-				stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, destinationTile));
+				stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, destinationTile, flags));
 		}
 	}
 }
@@ -606,7 +615,7 @@ void CBattleInterface::displaySpellCast(SpellID spellID, BattleHex destinationTi
 	const CSpell * spell = spellID.toSpell();
 
 	if(spell)
-		displaySpellAnimationQueue(spell->animationInfo.cast, destinationTile);
+		displaySpellAnimationQueue(spell->animationInfo.cast, destinationTile, false);
 }
 
 void CBattleInterface::displaySpellEffect(SpellID spellID, BattleHex destinationTile)
@@ -614,7 +623,7 @@ void CBattleInterface::displaySpellEffect(SpellID spellID, BattleHex destination
 	const CSpell *spell = spellID.toSpell();
 
 	if(spell)
-		displaySpellAnimationQueue(spell->animationInfo.affect, destinationTile);
+		displaySpellAnimationQueue(spell->animationInfo.affect, destinationTile, false);
 }
 
 void CBattleInterface::displaySpellHit(SpellID spellID, BattleHex destinationTile)
@@ -622,7 +631,7 @@ void CBattleInterface::displaySpellHit(SpellID spellID, BattleHex destinationTil
 	const CSpell * spell = spellID.toSpell();
 
 	if(spell)
-		displaySpellAnimationQueue(spell->animationInfo.hit, destinationTile);
+		displaySpellAnimationQueue(spell->animationInfo.hit, destinationTile, true);
 }
 
 void CBattleInterface::setAnimSpeed(int set)

+ 1 - 1
client/battle/CBattleInterface.h

@@ -166,7 +166,7 @@ public:
 
 	void displayBattleLog(const std::vector<MetaString> & battleLog);
 
-	void displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile);
+	void displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile, bool isHit);
 	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

+ 6 - 10
client/battle/CBattleObstacleController.cpp

@@ -85,15 +85,7 @@ void CBattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr
 			continue;
 		}
 
-		std::string defname = spellObstacle->appearAnimation;
-
-		//TODO: sound
-		//soundBase::QUIKSAND
-		//soundBase::LANDMINE
-		//soundBase::FORCEFLD
-		//soundBase::fireWall
-
-		auto animation = std::make_shared<CAnimation>(defname);
+		auto animation = std::make_shared<CAnimation>(spellObstacle->appearAnimation);
 		animation->preload();
 
 		auto first = animation->getImage(0, 0);
@@ -103,10 +95,14 @@ void CBattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr
 			continue;
 		}
 
+		//TODO: sound
+		//soundBase::QUIKSAND
+		//soundBase::LANDMINE
+
 		//we assume here that effect graphics have the same size as the usual obstacle image
 		// -> if we know how to blit obstacle, let's blit the effect in the same place
 		Point whereTo = getObstaclePosition(first, *oi);
-		owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::QUIKSAND, defname, whereTo, CPointEffectAnimation::WAIT_FOR_SOUND));
+		owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::invalid, spellObstacle->appearAnimation, whereTo, oi->pos, CPointEffectAnimation::WAIT_FOR_SOUND));
 
 		//so when multiple obstacles are added, they show up one after another
 		owner->waitForAnims();

+ 1 - 1
client/battle/CBattleSiegeController.cpp

@@ -333,7 +333,7 @@ void CBattleSiegeController::stackIsCatapulting(const CatapultAttack & ca)
 			positions.push_back(owner->stacksController->getStackPositionAtHex(attackInfo.destinationTile, nullptr) + Point(99, 120));
 
 
-		owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::invalid, "SGEXPL.DEF", positions));
+		owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::WALLHIT, "SGEXPL.DEF", positions));
 	}
 
 	owner->waitForAnims();