Kaynağa Gözat

Implemented group attack animations for dragons/Hydras/etc

Ivan Savenko 2 yıl önce
ebeveyn
işleme
7857668158

+ 74 - 68
client/battle/BattleAnimationClasses.cpp

@@ -92,6 +92,18 @@ BattleStackAnimation::BattleStackAnimation(BattleInterface & owner, const CStack
 	assert(myAnim);
 }
 
+ECreatureAnimType::Type AttackAnimation::findValidGroup( const std::vector<ECreatureAnimType::Type> candidates ) const
+{
+	for ( auto group : candidates)
+	{
+		if(myAnim->framesInGroup(group) > 0)
+			return group;
+	}
+
+	assert(0);
+	return ECreatureAnimType::HOLDING;
+}
+
 void AttackAnimation::nextFrame()
 {
 	if(myAnim->getType() != group)
@@ -210,6 +222,42 @@ void DummyAnimation::nextFrame()
 		delete this;
 }
 
+ECreatureAnimType::Type MeleeAttackAnimation::getUpwardsGroup() const
+{
+	if (!multiAttack)
+		return ECreatureAnimType::ATTACK_UP;
+
+	return findValidGroup({
+		ECreatureAnimType::GROUP_ATTACK_UP,
+		ECreatureAnimType::SPECIAL_UP,
+		ECreatureAnimType::ATTACK_UP
+	});
+}
+
+ECreatureAnimType::Type MeleeAttackAnimation::getForwardGroup() const
+{
+	if (!multiAttack)
+		return ECreatureAnimType::ATTACK_FRONT;
+
+	return findValidGroup({
+		ECreatureAnimType::GROUP_ATTACK_FRONT,
+		ECreatureAnimType::SPECIAL_FRONT,
+		ECreatureAnimType::ATTACK_FRONT
+	});
+}
+
+ECreatureAnimType::Type MeleeAttackAnimation::getDownwardsGroup() const
+{
+	if (!multiAttack)
+		return ECreatureAnimType::ATTACK_DOWN;
+
+	return findValidGroup({
+		ECreatureAnimType::GROUP_ATTACK_DOWN,
+		ECreatureAnimType::SPECIAL_DOWN,
+		ECreatureAnimType::ATTACK_DOWN
+	});
+}
+
 bool MeleeAttackAnimation::init()
 {
 	assert(attackingStack);
@@ -223,24 +271,14 @@ bool MeleeAttackAnimation::init()
 
 	logAnim->info("CMeleeAttackAnimation::init: stack %s -> stack %s", stack->getName(), defendingStack->getName());
 
-	static const ECreatureAnimType::Type mutPosToGroup[] =
-	{
-		ECreatureAnimType::ATTACK_UP,
-		ECreatureAnimType::ATTACK_UP,
-		ECreatureAnimType::ATTACK_FRONT,
-		ECreatureAnimType::ATTACK_DOWN,
-		ECreatureAnimType::ATTACK_DOWN,
-		ECreatureAnimType::ATTACK_FRONT
-	};
-
-	static const ECreatureAnimType::Type mutPosToGroup2H[] =
+	const ECreatureAnimType::Type mutPosToGroup[] =
 	{
-		ECreatureAnimType::VCMI_2HEX_UP,
-		ECreatureAnimType::VCMI_2HEX_UP,
-		ECreatureAnimType::VCMI_2HEX_FRONT,
-		ECreatureAnimType::VCMI_2HEX_DOWN,
-		ECreatureAnimType::VCMI_2HEX_DOWN,
-		ECreatureAnimType::VCMI_2HEX_FRONT
+		getUpwardsGroup(),
+		getUpwardsGroup(),
+		getForwardGroup(),
+		getDownwardsGroup(),
+		getDownwardsGroup(),
+		getForwardGroup()
 	};
 
 	int revShiftattacker = (attackingStack->side == BattleSide::ATTACKER ? -1 : 1);
@@ -259,30 +297,9 @@ bool MeleeAttackAnimation::init()
 		mutPos = BattleHex::mutualPosition(attackingStackPosBeforeReturn + revShiftattacker, defendingStack->occupiedHex());
 	}
 
+	assert(mutPos >= 0 && mutPos <=5);
 
-	switch(mutPos) //attack direction
-	{
-	case 0:
-	case 1:
-	case 2:
-	case 3:
-	case 4:
-	case 5:
-		group = mutPosToGroup[mutPos];
-		if(attackingStack->hasBonusOfType(Bonus::TWO_HEX_ATTACK_BREATH))
-		{
-			ECreatureAnimType::Type group2H = mutPosToGroup2H[mutPos];
-			if(myAnim->framesInGroup(group2H)>0)
-				group = group2H;
-		}
-
-		break;
-	default:
-		logGlobal->error("Critical Error! Wrong dest in stackAttacking! dest: %d; attacking stack pos: %d; mutual pos: %d", dest.hex, attackingStackPosBeforeReturn, mutPos);
-		group = ECreatureAnimType::ATTACK_FRONT;
-		break;
-	}
-
+	group = mutPosToGroup[mutPos];
 	return true;
 }
 
@@ -304,8 +321,9 @@ void MeleeAttackAnimation::playSound()
 	CCS->soundh->playSound(battle_sound(getCreature(), attack));
 }
 
-MeleeAttackAnimation::MeleeAttackAnimation(BattleInterface & owner, const CStack * attacker, BattleHex _dest, const CStack * _attacked)
-	: AttackAnimation(owner, attacker, _dest, _attacked)
+MeleeAttackAnimation::MeleeAttackAnimation(BattleInterface & owner, const CStack * attacker, BattleHex _dest, const CStack * _attacked, bool multiAttack)
+	: AttackAnimation(owner, attacker, _dest, _attacked),
+	  multiAttack(multiAttack)
 {
 	logAnim->debug("Created melee attack anim for %s", attacker->getName());
 }
@@ -603,17 +621,17 @@ void FadingAnimation::nextFrame()
 	float delta    = elapsed / fullTime;
 	progress += delta;
 
-	if (progress > 1.0f)
-		progress = 1.0f;
-
-	uint8_t factor = stack->cloned ? 128 : 255;
-	uint8_t blue   = stack->cloned ? 128 : 0;
-	uint8_t alpha  = CSDL_Ext::lerp(from, dest, progress);
-
-	ColorShifterMultiplyAndAdd shifterFade ({factor, factor, factor, alpha}, {0, 0, blue, 0});
-	stackAnimation(stack)->shiftColor(&shifterFade);
-
-	if (progress == 1.0f)
+	if (progress > 1.0f)
+		progress = 1.0f;
+
+	uint8_t factor = stack->cloned ? 128 : 255;
+	uint8_t blue   = stack->cloned ? 128 : 0;
+	uint8_t alpha  = CSDL_Ext::lerp(from, dest, progress);
+
+	ColorShifterMultiplyAndAdd shifterFade ({factor, factor, factor, alpha}, {0, 0, blue, 0});
+	stackAnimation(stack)->shiftColor(&shifterFade);
+
+	if (progress == 1.0f)
 		delete this;
 }
 
@@ -831,23 +849,11 @@ CastAnimation::CastAnimation(BattleInterface & owner_, const CStack * attacker,
 		dest = defender->getPosition();
 }
 
-ECreatureAnimType::Type CastAnimation::findValidGroup( const std::vector<ECreatureAnimType::Type> candidates ) const
-{
-	for ( auto group : candidates)
-	{
-		if(myAnim->framesInGroup(group) > 0)
-			return group;
-	}
-
-	assert(0);
-	return ECreatureAnimType::HOLDING;
-}
-
 ECreatureAnimType::Type CastAnimation::getUpwardsGroup() const
 {
 	return findValidGroup({
-		ECreatureAnimType::VCMI_CAST_UP,
 		ECreatureAnimType::CAST_UP,
+		ECreatureAnimType::SPECIAL_UP,
 		ECreatureAnimType::SHOOT_UP,
 		ECreatureAnimType::ATTACK_UP
 	});
@@ -856,8 +862,8 @@ ECreatureAnimType::Type CastAnimation::getUpwardsGroup() const
 ECreatureAnimType::Type CastAnimation::getForwardGroup() const
 {
 	return findValidGroup({
-		ECreatureAnimType::VCMI_CAST_FRONT,
 		ECreatureAnimType::CAST_FRONT,
+		ECreatureAnimType::SPECIAL_FRONT,
 		ECreatureAnimType::SHOOT_FRONT,
 		ECreatureAnimType::ATTACK_FRONT
 	});
@@ -866,8 +872,8 @@ ECreatureAnimType::Type CastAnimation::getForwardGroup() const
 ECreatureAnimType::Type CastAnimation::getDownwardsGroup() const
 {
 	return findValidGroup({
-		ECreatureAnimType::VCMI_CAST_DOWN,
 		ECreatureAnimType::CAST_DOWN,
+		ECreatureAnimType::SPECIAL_DOWN,
 		ECreatureAnimType::SHOOT_DOWN,
 		ECreatureAnimType::ATTACK_DOWN
 	});

+ 7 - 1
client/battle/BattleAnimationClasses.h

@@ -76,6 +76,8 @@ protected:
 	int attackingStackPosBeforeReturn; //for stacks with return_after_strike feature
 
 	const CCreature * getCreature() const;
+	ECreatureAnimType::Type findValidGroup( const std::vector<ECreatureAnimType::Type> candidates ) const;
+
 public:
 	virtual void playSound() = 0;
 
@@ -127,6 +129,11 @@ public:
 class MeleeAttackAnimation : public AttackAnimation
 {
 	bool multiAttack;
+
+	ECreatureAnimType::Type getUpwardsGroup() const;
+	ECreatureAnimType::Type getForwardGroup() const;
+	ECreatureAnimType::Type getDownwardsGroup() const;
+
 public:
 	bool init() override;
 	void nextFrame() override;
@@ -278,7 +285,6 @@ class CastAnimation : public RangedAttackAnimation
 {
 	const CSpell * spell;
 
-	ECreatureAnimType::Type findValidGroup( const std::vector<ECreatureAnimType::Type> candidates ) const;
 	ECreatureAnimType::Type getUpwardsGroup() const override;
 	ECreatureAnimType::Type getForwardGroup() const override;
 	ECreatureAnimType::Type getDownwardsGroup() const override;

+ 10 - 9
client/battle/BattleConstants.h

@@ -73,9 +73,9 @@ enum Type // list of creature animations, numbers were taken from def files
 	SHOOT_UP        = 14, // Shooters only
 	SHOOT_FRONT     = 15, // Shooters only
 	SHOOT_DOWN      = 16, // Shooters only
-	CAST_UP         = 17, // If empty, fallback to CAST_FRONT
-	CAST_FRONT      = 18, // Used for any special moves - dragon breath, spellcasting, (possibly - Pit Lord/Ogre Mage ability)
-	CAST_DOWN       = 19, // If empty, fallback to CAST_FRONT
+	SPECIAL_UP      = 17, // If empty, fallback to SPECIAL_FRONT
+	SPECIAL_FRONT   = 18, // Used for any special moves - dragon breath, spellcasting, (possibly - Pit Lord/Ogre Mage ability)
+	SPECIAL_DOWN    = 19, // If empty, fallback to SPECIAL_FRONT
 	MOVE_START      = 20, // small animation to be played before MOVING
 	MOVE_END        = 21, // small animation to be played after MOVING
 
@@ -83,11 +83,12 @@ enum Type // list of creature animations, numbers were taken from def files
 	DEAD_RANGED     = 23, // new group, used to show dead stacks (if DEATH_RANGED was used). If empty - last frame from "DEATH_RANGED" will be copied here
 	RESURRECTION    = 24, // new group, used for animating resurrection, if empty - reversed "DEATH" animation will be copiend here
 
-	VCMI_CAST_UP    = 30,
-	VCMI_CAST_FRONT = 31,
-	VCMI_CAST_DOWN  = 32,
-	VCMI_2HEX_UP    = 40,
-	VCMI_2HEX_FRONT = 41,
-	VCMI_2HEX_DOWN  = 42
+	CAST_UP            = 30,
+	CAST_FRONT         = 31,
+	CAST_DOWN          = 32,
+
+	GROUP_ATTACK_UP    = 40,
+	GROUP_ATTACK_FRONT = 41,
+	GROUP_ATTACK_DOWN  = 42
 };
 }

+ 2 - 1
client/battle/BattleStacksController.cpp

@@ -513,6 +513,7 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
 	auto defender    = info.defender;
 	auto tile        = info.tile;
 	auto spellEffect = info.spellEffect;
+	auto multiAttack = !info.secondaryDefender.empty();
 
 	if (needsReverse)
 	{
@@ -561,7 +562,7 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
 		}
 		else
 		{
-			addNewAnim(new MeleeAttackAnimation(owner, attacker, tile, defender));
+			addNewAnim(new MeleeAttackAnimation(owner, attacker, tile, defender, multiAttack));
 		}
 	});
 

+ 21 - 21
client/battle/CreatureAnimation.cpp

@@ -74,12 +74,12 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c
 	case ECreatureAnimType::SHOOT_UP:
 	case ECreatureAnimType::SHOOT_FRONT:
 	case ECreatureAnimType::SHOOT_DOWN:
-	case ECreatureAnimType::CAST_UP:
-	case ECreatureAnimType::CAST_FRONT:
+	case ECreatureAnimType::SPECIAL_UP:
+	case ECreatureAnimType::SPECIAL_FRONT:
+	case ECreatureAnimType::SPECIAL_DOWN:
 	case ECreatureAnimType::CAST_DOWN:
-	case ECreatureAnimType::VCMI_CAST_DOWN:
-	case ECreatureAnimType::VCMI_CAST_FRONT:
-	case ECreatureAnimType::VCMI_CAST_UP:
+	case ECreatureAnimType::CAST_FRONT:
+	case ECreatureAnimType::CAST_UP:
 		return static_cast<float>(speed * 4 * creature->animation.attackAnimationTime / anim->framesInGroup(type));
 
 	// as strange as it looks like "attackAnimationTime" does not affects melee attacks
@@ -92,9 +92,9 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c
 	case ECreatureAnimType::DEATH:
 	case ECreatureAnimType::DEATH_RANGED:
 	case ECreatureAnimType::RESURRECTION:
-	case ECreatureAnimType::VCMI_2HEX_DOWN:
-	case ECreatureAnimType::VCMI_2HEX_FRONT:
-	case ECreatureAnimType::VCMI_2HEX_UP:
+	case ECreatureAnimType::GROUP_ATTACK_DOWN:
+	case ECreatureAnimType::GROUP_ATTACK_FRONT:
+	case ECreatureAnimType::GROUP_ATTACK_UP:
 		return speed * 3 / anim->framesInGroup(type);
 
 	case ECreatureAnimType::TURN_L:
@@ -315,19 +315,19 @@ static SDL_Color addColors(const SDL_Color & base, const SDL_Color & over)
 			ui8(over.a + base.a * (255 - over.a) / 256)
 			);
 }
-
-void CreatureAnimation::genSpecialPalette(IImage::SpecialPalette & target)
-{
-	target[0] = genShadow(shadowAlpha / 2);
-	target[1] = genShadow(shadowAlpha / 2);
-	target[2] = genShadow(shadowAlpha);
-	target[3] = genShadow(shadowAlpha);
-	target[4] = genBorderColor(getBorderStrength(elapsedTime), border);
-	target[5] = addColors(genShadow(shadowAlpha),     genBorderColor(getBorderStrength(elapsedTime), border));
-	target[6] = addColors(genShadow(shadowAlpha / 2), genBorderColor(getBorderStrength(elapsedTime), border));
-}
-
-void CreatureAnimation::nextFrame(Canvas & canvas, bool facingRight)
+
+void CreatureAnimation::genSpecialPalette(IImage::SpecialPalette & target)
+{
+	target[0] = genShadow(shadowAlpha / 2);
+	target[1] = genShadow(shadowAlpha / 2);
+	target[2] = genShadow(shadowAlpha);
+	target[3] = genShadow(shadowAlpha);
+	target[4] = genBorderColor(getBorderStrength(elapsedTime), border);
+	target[5] = addColors(genShadow(shadowAlpha),     genBorderColor(getBorderStrength(elapsedTime), border));
+	target[6] = addColors(genShadow(shadowAlpha / 2), genBorderColor(getBorderStrength(elapsedTime), border));
+}
+
+void CreatureAnimation::nextFrame(Canvas & canvas, bool facingRight)
 {
 	size_t frame = static_cast<size_t>(floor(currentFrame));
 

+ 1 - 1
client/widgets/Images.cpp

@@ -482,7 +482,7 @@ void CCreatureAnim::loopPreview(bool warMachine)
 		ECreatureAnimType::HITTED,
 		ECreatureAnimType::DEFENCE,
 		ECreatureAnimType::ATTACK_FRONT,
-		ECreatureAnimType::CAST_FRONT
+		ECreatureAnimType::SPECIAL_FRONT
 	};
 	static const ECreatureAnimType::Type machPreviewList[] = {
 		ECreatureAnimType::HOLDING,