Pārlūkot izejas kodu

* spell animations are handled by new battle animation engine
* armageddon works when there are dead stack on the battlefield

mateuszb 16 gadi atpakaļ
vecāks
revīzija
451c08922c
3 mainītis faili ar 172 papildinājumiem un 93 dzēšanām
  1. 145 86
      client/CBattleInterface.cpp
  2. 25 6
      client/CBattleInterface.h
  3. 2 1
      lib/CGameState.cpp

+ 145 - 86
client/CBattleInterface.cpp

@@ -113,6 +113,136 @@ CBattleAnimation::CBattleAnimation(CBattleInterface * _owner)
 : owner(_owner), ID(_owner->animIDhelper++)
 {}
 
+//effect animation
+bool CSpellEffectAnim::init()
+{
+	if(!isEarliest(false))
+		return false;
+
+	if(effect == 12) //armageddon
+	{
+		if(effect == -1 || graphics->battleACToDef[effect].size() != 0)
+		{
+			CDefHandler * anim;
+			if(customAnim.size())
+				anim = CDefHandler::giveDef(customAnim);
+			else
+				anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
+
+			for(int i=0; i * anim->width < owner->pos.w ; ++i)
+			{
+				for(int j=0; j * anim->height < owner->pos.h ; ++j)
+				{
+					SBattleEffect be;
+					be.effectID = ID;
+					be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
+					be.frame = 0;
+					be.maxFrame = be.anim->ourImages.size();
+					be.x = i * anim->width;
+					be.y = j * anim->height;
+
+					owner->battleEffects.push_back(be);
+				}
+			}
+		}
+	}
+	else // Effects targeted at a specific creature/hex.
+	{
+		if(effect == -1 || graphics->battleACToDef[effect].size() != 0)
+		{
+			const CStack* destStack = LOCPLINT->cb->battleGetStackByPos(destTile, false);
+			Rect &tilePos = owner->bfield[destTile].pos;
+			SBattleEffect be;
+			be.effectID = ID;
+			if(customAnim.size())
+				be.anim = CDefHandler::giveDef(customAnim);
+			else
+				be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
+			be.frame = 0;
+			be.maxFrame = be.anim->ourImages.size();
+
+			switch (effect)
+			{
+			case -1:
+				be.x = x;
+				be.y = y;
+				break;
+			case 0: // Prayer and Lightning Bolt.
+			case 1:
+				// Position effect with it's bottom center touching the bottom center of affected tile(s).
+				be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
+				be.y = tilePos.y + tilePos.h - be.anim->height;
+				break;
+
+			default:
+				// Position effect with it's center touching the top center of affected tile(s).
+				be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
+				be.y = tilePos.y - be.anim->height/2;
+				break;
+			}
+
+			// Correction for 2-hex creatures.
+			if (destStack != NULL && destStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
+				be.x += (destStack->attackerOwned ? -1 : 1)*tilePos.w/2;
+
+			owner->battleEffects.push_back(be);
+		}
+	}
+	//battleEffects 
+	return true;
+}
+
+void CSpellEffectAnim::nextFrame()
+{
+	for(std::list<SBattleEffect>::iterator it = owner->battleEffects.begin(); it != owner->battleEffects.end(); ++it)
+	{
+		++(it->frame);
+
+		if(it->frame == it->maxFrame)
+		{
+			endAnim();
+			break;
+		}
+		else
+		{
+			it->x += dx;
+			it->y += dy;
+		}
+	}
+}
+
+void CSpellEffectAnim::endAnim()
+{
+	CBattleAnimation::endAnim();
+
+	std::vector<std::list<SBattleEffect>::iterator> toDel;
+
+	for(std::list<SBattleEffect>::iterator it = owner->battleEffects.begin(); it != owner->battleEffects.end(); ++it)
+	{
+		if(it->effectID == ID)
+		{
+			toDel.push_back(it);
+		}
+	}
+
+	for(int b=0; b<toDel.size(); ++b)
+	{
+		owner->battleEffects.erase(toDel[b]);
+	}
+
+	delete this;
+}
+
+CSpellEffectAnim::CSpellEffectAnim(CBattleInterface * _owner, ui32 _effect, int _destTile, int _dx, int _dy)
+:CBattleAnimation(_owner), effect(_effect), destTile(_destTile), customAnim(""), dx(_dx), dy(_dy)
+{
+}
+
+CSpellEffectAnim::CSpellEffectAnim(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx, int _dy)
+:CBattleAnimation(_owner), effect(-1), destTile(0), customAnim(_customAnim), x(_x), y(_y), dx(_dx), dy(_dy)
+{
+}
+
 //stack's aniamtion
 
 CBattleStackAnimation::CBattleStackAnimation(CBattleInterface * _owner, int stack)
@@ -250,6 +380,9 @@ bool CDefenceAnim::init()
 	//	return false;
 	//}
 
+	if(IDby == -1 && owner->battleEffects.size() > 0)
+		return false;
+
 	int lowestMoveID = owner->animIDhelper + 5;
 	for(std::list<std::pair<CBattleAnimation *, bool> >::iterator it = owner->pendingAnims.begin(); it != owner->pendingAnims.end(); ++it)
 	{
@@ -261,9 +394,12 @@ bool CDefenceAnim::init()
 			continue;
 
 		const CStack * attacker = LOCPLINT->cb->battleGetStackByID(IDby, false);
-		int attackerAnimType = owner->creAnims[IDby]->getType();
-		if( attackerAnimType == 11 && attackerAnimType == 12 && attackerAnimType == 13 && owner->creAnims[IDby]->getFrame() < attacker->creature->attackClimaxFrame )
-			return false;
+		if(IDby != -1)
+		{
+			int attackerAnimType = owner->creAnims[IDby]->getType();
+			if( attackerAnimType == 11 && attackerAnimType == 12 && attackerAnimType == 13 && owner->creAnims[IDby]->getFrame() < attacker->creature->attackClimaxFrame )
+				return false;
+		}
 
 		CReverseAnim * animAsRev = dynamic_cast<CReverseAnim *>(it->first);
 
@@ -281,7 +417,7 @@ bool CDefenceAnim::init()
 	const CStack * attacked = LOCPLINT->cb->battleGetStackByID(stackID, false);
 
 	//reverse unit if necessary
-	if(isToReverse(attacked->position, attacker->position, owner->creDir[stackID], attacker->hasFeatureOfType(StackFeature::DOUBLE_WIDE), owner->creDir[IDby]))
+	if(attacker && isToReverse(attacked->position, attacker->position, owner->creDir[stackID], attacker->hasFeatureOfType(StackFeature::DOUBLE_WIDE), owner->creDir[IDby]))
 	{
 		owner->addNewAnim(new CReverseAnim(owner, stackID, attacked->position, true));
 		return false;
@@ -1388,22 +1524,10 @@ void CBattleInterface::show(SDL_Surface * to)
 	//showing spell effects
 	if(battleEffects.size())
 	{
-		std::vector< std::list<SBattleEffect>::iterator > toErase;
 		for(std::list<SBattleEffect>::iterator it = battleEffects.begin(); it!=battleEffects.end(); ++it)
 		{
 			SDL_Surface * bitmapToBlit = it->anim->ourImages[(it->frame)%it->anim->ourImages.size()].bitmap;
 			SDL_BlitSurface(bitmapToBlit, NULL, to, &genRect(bitmapToBlit->h, bitmapToBlit->w, pos.x + it->x, pos.y + it->y));
-			++(it->frame);
-
-			if(it->frame == it->maxFrame)
-			{
-				toErase.push_back(it);
-			}
-		}
-		for(size_t b=0; b<toErase.size(); ++b)
-		{
-			delete toErase[b]->anim;
-			battleEffects.erase(toErase[b]);
 		}
 	}
 	
@@ -2319,27 +2443,16 @@ void CBattleInterface::spellCast(SpellCast * sc)
 				animToDisplay = anims[4];
 
 			//displaying animation
+			CDefEssential * animDef = CDefHandler::giveDefEss(animToDisplay);
 			int steps = sqrt((float)((destcoord.first - srccoord.first)*(destcoord.first - srccoord.first) + (destcoord.second - srccoord.second) * (destcoord.second - srccoord.second))) / 40;
 			if(steps <= 0)
 				steps = 1;
 
-			CDefHandler * animDef = CDefHandler::giveDef(animToDisplay);
-
 			int dx = (destcoord.first - srccoord.first - animDef->ourImages[0].bitmap->w)/steps, dy = (destcoord.second - srccoord.second - animDef->ourImages[0].bitmap->h)/steps;
 
-			SDL_Rect buf;
-			SDL_GetClipRect(screen, &buf);
-			SDL_SetClipRect(screen, &pos); //setting rect we can blit to
-			for(int g=0; g<steps; ++g)
-			{
-				show(screen);
-				SDL_Rect & srcr = animDef->ourImages[g%animDef->ourImages.size()].bitmap->clip_rect;
-				SDL_Rect dstr = genRect(srcr.h, srcr.w, srccoord.first + g*dx, srccoord.second + g*dy);
-				SDL_BlitSurface(animDef->ourImages[g%animDef->ourImages.size()].bitmap, &srcr, screen, &dstr);
-				CSDL_Ext::update(screen);
-				SDL_framerateDelay(LOCPLINT->mainFPSmng);
-			}
-			SDL_SetClipRect(screen, &buf); //restoring previous clip rect
+			delete animDef;
+			addNewAnim(new CSpellEffectAnim(this, animToDisplay, srccoord.first, srccoord.second, dx, dy));
+
 			break; //for 15 and 16 cases
 		}
 	case 17: //lightning bolt
@@ -2447,61 +2560,7 @@ void CBattleInterface::castThisSpell(int spellID)
 
 void CBattleInterface::displayEffect(ui32 effect, int destTile)
 {
-	if(effect == 12) //armageddon
-	{
-		if(graphics->battleACToDef[effect].size() != 0)
-		{
-			CDefHandler * anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
-			for(int i=0; i * anim->width < pos.w ; ++i)
-			{
-				for(int j=0; j * anim->height < pos.h ; ++j)
-				{
-					SBattleEffect be;
-					be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
-					be.frame = 0;
-					be.maxFrame = be.anim->ourImages.size();
-					be.x = i * anim->width;
-					be.y = j * anim->height;
-
-					battleEffects.push_back(be);
-				}
-			}
-		}
-	}
-	else // Effects targeted at a specific creature/hex.
-	{
-		if(graphics->battleACToDef[effect].size() != 0)
-		{
-			const CStack* destStack = LOCPLINT->cb->battleGetStackByPos(destTile, false);
-			Rect &tilePos = bfield[destTile].pos;
-			SBattleEffect be;
-			be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
-			be.frame = 0;
-			be.maxFrame = be.anim->ourImages.size();
-
-			switch (effect) {
-				case 0: // Prayer and Lightning Bolt.
-				case 1:
-					// Position effect with it's bottom center touching the bottom center of affected tile(s).
-					be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
-					be.y = tilePos.y + tilePos.h - be.anim->height;
-					break;
-
-				default:
-					// Position effect with it's center touching the top center of affected tile(s).
-					be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
-					be.y = tilePos.y - be.anim->height/2;
-					break;
-			}
-
-			// Correction for 2-hex creatures.
-			if (destStack != NULL && destStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
-				be.x += (destStack->attackerOwned ? -1 : 1)*tilePos.w/2;
-
-			battleEffects.push_back(be);
-		}
-	}
-	//battleEffects 
+	addNewAnim(new CSpellEffectAnim(this, effect, destTile));
 }
 
 void CBattleInterface::setAnimSpeed(int set)

+ 25 - 6
client/CBattleInterface.h

@@ -72,6 +72,22 @@ public:
 	CBattleAnimation(CBattleInterface * _owner);
 };
 
+class CSpellEffectAnim : public CBattleAnimation
+{
+private:
+	ui32 effect;
+	int destTile;
+	std::string customAnim;
+	int x, y, dx, dy;
+public:
+	bool init();
+	void nextFrame();
+	void endAnim();
+
+	CSpellEffectAnim(CBattleInterface * _owner, ui32 _effect, int _destTile, int _dx = 0, int _dy = 0);
+	CSpellEffectAnim(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0);
+};
+
 class CBattleStackAnimation : public CBattleAnimation
 {
 public:
@@ -319,6 +335,14 @@ struct BattleSettings
 	}
 };
 
+struct SBattleEffect
+{
+	int x, y; //position on the screen
+	int frame, maxFrame;
+	CDefHandler * anim; //animation to display
+	int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim
+};
+
 class CBattleInterface : public CIntObject
 {
 private:
@@ -361,12 +385,6 @@ private:
 	bool blockedByObstacle(int hex) const;
 	bool isCatapultAttackable(int hex) const; //returns true if given tile can be attacked by catapult
 
-	struct SBattleEffect
-	{
-		int x, y; //position on the screen
-		int frame, maxFrame;
-		CDefHandler * anim; //animation to display
-	};
 	std::list<SBattleEffect> battleEffects; //different animations to display on the screen like spell effects
 
 	class SiegeHelper
@@ -468,6 +486,7 @@ public:
 	friend class CBattleAttack;
 	friend class CMeleeAttack;
 	friend class CShootingAnim;
+	friend class CSpellEffectAnim;
 };
 
 #endif // __CBATTLEINTERFACE_H__

+ 2 - 1
lib/CGameState.cpp

@@ -2540,7 +2540,8 @@ std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, const CGHer
 				|| (s->id == 26) //Armageddon
 				)
 			{
-				attackedCres.insert(stacks[it]);
+				if(stacks[it]->alive())
+					attackedCres.insert(stacks[it]);
 			}
 		}
 	}