mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
Implemented group attack animations for dragons/Hydras/etc
This commit is contained in:
parent
814f6ed684
commit
7857668158
@ -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[] =
|
||||
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[] =
|
||||
{
|
||||
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
|
||||
});
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user