2017-07-13 10:26:03 +02:00
/*
2022-12-11 23:16:23 +02:00
* BattleAnimationClasses . cpp , part of VCMI engine
2017-07-13 10:26:03 +02:00
*
* 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
*
*/
2011-12-22 16:05:19 +03:00
# include "StdInc.h"
2022-12-09 13:38:46 +02:00
# include "BattleAnimationClasses.h"
2011-12-22 16:05:19 +03:00
2022-12-09 13:38:46 +02:00
# include "BattleInterface.h"
2022-12-13 18:49:35 +02:00
# include "BattleInterfaceClasses.h"
2022-12-09 13:38:46 +02:00
# include "BattleProjectileController.h"
# include "BattleSiegeController.h"
# include "BattleFieldController.h"
# include "BattleEffectsController.h"
# include "BattleStacksController.h"
# include "CreatureAnimation.h"
2013-07-06 19:10:20 +03:00
# include "../CGameInfo.h"
# include "../CMusicHandler.h"
2011-12-22 16:05:19 +03:00
# include "../CPlayerInterface.h"
2023-01-05 19:34:37 +02:00
# include "../gui/CursorHandler.h"
2013-07-06 19:10:20 +03:00
# include "../gui/CGuiHandler.h"
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
# include "../../CCallback.h"
2017-03-17 17:48:44 +02:00
# include "../../lib/CStack.h"
2011-12-22 16:05:19 +03:00
2022-12-12 22:04:25 +02:00
BattleAnimation : : BattleAnimation ( BattleInterface & owner )
2022-12-13 13:58:16 +02:00
: owner ( owner ) ,
ID ( owner . stacksController - > animIDhelper + + ) ,
2022-11-28 16:02:46 +02:00
initialized ( false )
2013-07-16 21:12:47 +03:00
{
2017-08-10 22:47:58 +02:00
logAnim - > trace ( " Animation #%d created " , ID ) ;
2013-07-16 21:12:47 +03:00
}
2022-12-12 22:04:25 +02:00
bool BattleAnimation : : tryInitialize ( )
2013-07-16 21:12:47 +03:00
{
2022-11-28 16:02:46 +02:00
assert ( ! initialized ) ;
if ( init ( ) )
{
initialized = true ;
return true ;
}
return false ;
2013-07-16 21:12:47 +03:00
}
2011-12-22 16:05:19 +03:00
2022-12-12 22:04:25 +02:00
bool BattleAnimation : : isInitialized ( )
2022-11-20 19:11:34 +02:00
{
2022-11-28 16:02:46 +02:00
return initialized ;
2022-11-20 19:11:34 +02:00
}
2022-12-12 22:04:25 +02:00
BattleAnimation : : ~ BattleAnimation ( )
2022-11-20 19:11:34 +02:00
{
2022-11-28 16:02:46 +02:00
logAnim - > trace ( " Animation #%d ended, type is %s " , ID , typeid ( this ) . name ( ) ) ;
for ( auto & elem : pendingAnimations ( ) )
{
if ( elem = = this )
elem = nullptr ;
}
logAnim - > trace ( " Animation #%d deleted " , ID ) ;
2022-11-20 19:11:34 +02:00
}
2022-12-12 22:04:25 +02:00
std : : vector < BattleAnimation * > & BattleAnimation : : pendingAnimations ( )
2022-11-20 19:11:34 +02:00
{
2022-12-13 13:58:16 +02:00
return owner . stacksController - > currentAnimations ;
2022-11-20 19:11:34 +02:00
}
2022-12-12 22:04:25 +02:00
std : : shared_ptr < CreatureAnimation > BattleAnimation : : stackAnimation ( const CStack * stack ) const
2022-11-20 19:11:34 +02:00
{
2023-04-27 19:43:20 +02:00
return owner . stacksController - > stackAnimation [ stack - > unitId ( ) ] ;
2022-11-20 19:11:34 +02:00
}
2022-12-12 22:04:25 +02:00
bool BattleAnimation : : stackFacingRight ( const CStack * stack )
2022-11-20 19:11:34 +02:00
{
2023-04-27 19:43:20 +02:00
return owner . stacksController - > stackFacingRight [ stack - > unitId ( ) ] ;
2022-11-20 19:11:34 +02:00
}
2022-12-12 22:04:25 +02:00
void BattleAnimation : : setStackFacingRight ( const CStack * stack , bool facingRight )
2011-12-22 16:05:19 +03:00
{
2023-04-27 19:43:20 +02:00
owner . stacksController - > stackFacingRight [ stack - > unitId ( ) ] = facingRight ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
BattleStackAnimation : : BattleStackAnimation ( BattleInterface & owner , const CStack * stack )
: BattleAnimation ( owner ) ,
2022-11-20 19:11:34 +02:00
myAnim ( stackAnimation ( stack ) ) ,
2020-10-06 01:27:04 +02:00
stack ( stack )
2013-09-27 22:42:17 +03:00
{
assert ( myAnim ) ;
}
2011-12-22 16:05:19 +03:00
2022-12-16 18:34:35 +02:00
StackActionAnimation : : StackActionAnimation ( BattleInterface & owner , const CStack * stack )
: BattleStackAnimation ( owner , stack )
, nextGroup ( ECreatureAnimType : : HOLDING )
, currGroup ( ECreatureAnimType : : HOLDING )
2022-12-14 14:21:58 +02:00
{
2022-12-16 18:34:35 +02:00
}
2022-12-14 14:21:58 +02:00
2022-12-22 01:04:58 +02:00
ECreatureAnimType StackActionAnimation : : getGroup ( ) const
2022-12-16 18:34:35 +02:00
{
return currGroup ;
}
2022-12-22 01:04:58 +02:00
void StackActionAnimation : : setNextGroup ( ECreatureAnimType group )
2022-12-16 18:34:35 +02:00
{
nextGroup = group ;
2022-12-14 14:21:58 +02:00
}
2022-12-22 01:04:58 +02:00
void StackActionAnimation : : setGroup ( ECreatureAnimType group )
2011-12-22 16:05:19 +03:00
{
2022-12-16 18:34:35 +02:00
currGroup = group ;
}
void StackActionAnimation : : setSound ( std : : string sound )
{
this - > sound = sound ;
}
bool StackActionAnimation : : init ( )
{
if ( ! sound . empty ( ) )
CCS - > soundh - > playSound ( sound ) ;
if ( myAnim - > framesInGroup ( currGroup ) > 0 )
2013-07-06 19:10:20 +03:00
{
2022-12-16 18:34:35 +02:00
myAnim - > playOnce ( currGroup ) ;
2022-11-28 16:02:46 +02:00
myAnim - > onAnimationReset + = [ & ] ( ) { delete this ; } ;
2013-07-06 19:10:20 +03:00
}
2022-12-16 18:34:35 +02:00
else
delete this ;
2011-12-22 16:05:19 +03:00
2022-12-16 18:34:35 +02:00
return true ;
2013-07-06 19:10:20 +03:00
}
2022-12-16 18:34:35 +02:00
StackActionAnimation : : ~ StackActionAnimation ( )
2013-07-06 19:10:20 +03:00
{
2023-04-20 17:12:10 +02:00
if ( stack - > isFrozen ( ) & & currGroup ! = ECreatureAnimType : : DEATH & & currGroup ! = ECreatureAnimType : : DEATH_RANGED )
2022-12-16 18:34:35 +02:00
myAnim - > setType ( ECreatureAnimType : : HOLDING ) ;
else
myAnim - > setType ( nextGroup ) ;
}
2022-12-22 01:04:58 +02:00
ECreatureAnimType AttackAnimation : : findValidGroup ( const std : : vector < ECreatureAnimType > candidates ) const
2022-12-16 18:34:35 +02:00
{
for ( auto group : candidates )
{
if ( myAnim - > framesInGroup ( group ) > 0 )
return group ;
}
assert ( 0 ) ;
return ECreatureAnimType : : HOLDING ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
const CCreature * AttackAnimation : : getCreature ( ) const
2022-11-27 20:01:52 +02:00
{
2023-04-12 00:52:12 +02:00
if ( attackingStack - > unitType ( ) - > getId ( ) = = CreatureID : : ARROW_TOWERS )
2022-12-13 13:58:16 +02:00
return owner . siegeController - > getTurretCreature ( ) ;
2022-11-27 20:01:52 +02:00
else
2023-04-12 00:52:12 +02:00
return attackingStack - > unitType ( ) ;
2022-11-27 20:01:52 +02:00
}
2022-12-12 22:04:25 +02:00
AttackAnimation : : AttackAnimation ( BattleInterface & owner , const CStack * attacker , BattleHex _dest , const CStack * defender )
2022-12-16 18:34:35 +02:00
: StackActionAnimation ( owner , attacker ) ,
2022-11-28 16:43:38 +02:00
dest ( _dest ) ,
2022-12-12 22:04:25 +02:00
defendingStack ( defender ) ,
2022-11-28 16:43:38 +02:00
attackingStack ( attacker )
2011-12-22 16:05:19 +03:00
{
2013-06-26 14:18:27 +03:00
assert ( attackingStack & & " attackingStack is nullptr in CBattleAttack::CBattleAttack ! \n " ) ;
2017-07-20 06:08:49 +02:00
attackingStackPosBeforeReturn = attackingStack - > getPosition ( ) ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
HittedAnimation : : HittedAnimation ( BattleInterface & owner , const CStack * stack )
2022-12-16 18:34:35 +02:00
: StackActionAnimation ( owner , stack )
2014-09-23 16:02:30 +03:00
{
2022-12-16 18:34:35 +02:00
setGroup ( ECreatureAnimType : : HITTED ) ;
2023-04-12 00:52:12 +02:00
setSound ( battle_sound ( stack - > unitType ( ) , wince ) ) ;
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Created HittedAnimation for %s " , stack - > getName ( ) ) ;
2014-09-23 16:02:30 +03:00
}
2011-12-22 16:05:19 +03:00
2022-12-12 22:04:25 +02:00
DefenceAnimation : : DefenceAnimation ( BattleInterface & owner , const CStack * stack )
2022-12-16 18:34:35 +02:00
: StackActionAnimation ( owner , stack )
2011-12-22 16:05:19 +03:00
{
2022-12-16 18:34:35 +02:00
setGroup ( ECreatureAnimType : : DEFENCE ) ;
2023-04-12 00:52:12 +02:00
setSound ( battle_sound ( stack - > unitType ( ) , defend ) ) ;
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Created DefenceAnimation for %s " , stack - > getName ( ) ) ;
2022-12-12 22:04:25 +02:00
}
2013-07-16 21:12:47 +03:00
2022-12-16 18:34:35 +02:00
DeathAnimation : : DeathAnimation ( BattleInterface & owner , const CStack * stack , bool ranged ) :
StackActionAnimation ( owner , stack )
2022-12-12 22:04:25 +02:00
{
2023-04-12 00:52:12 +02:00
setSound ( battle_sound ( stack - > unitType ( ) , killed ) ) ;
2011-12-22 16:05:19 +03:00
2022-12-16 18:34:35 +02:00
if ( ranged & & myAnim - > framesInGroup ( ECreatureAnimType : : DEATH_RANGED ) > 0 )
setGroup ( ECreatureAnimType : : DEATH_RANGED ) ;
2017-07-20 06:08:49 +02:00
else
2022-12-16 18:34:35 +02:00
setGroup ( ECreatureAnimType : : DEATH ) ;
2013-07-16 21:12:47 +03:00
2022-12-16 18:34:35 +02:00
if ( ranged & & myAnim - > framesInGroup ( ECreatureAnimType : : DEAD_RANGED ) > 0 )
setNextGroup ( ECreatureAnimType : : DEAD_RANGED ) ;
2013-07-06 19:10:20 +03:00
else
2022-12-16 18:34:35 +02:00
setNextGroup ( ECreatureAnimType : : DEAD ) ;
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Created DeathAnimation for %s " , stack - > getName ( ) ) ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
DummyAnimation : : DummyAnimation ( BattleInterface & owner , int howManyFrames )
: BattleAnimation ( owner ) ,
2022-11-28 16:43:38 +02:00
counter ( 0 ) ,
howMany ( howManyFrames )
2015-09-12 23:01:36 +02:00
{
2017-08-11 13:38:10 +02:00
logAnim - > debug ( " Created dummy animation for %d frames " , howManyFrames ) ;
2015-09-12 23:01:36 +02:00
}
2011-12-22 16:05:19 +03:00
2022-12-12 22:04:25 +02:00
bool DummyAnimation : : init ( )
2011-12-22 16:05:19 +03:00
{
return true ;
}
2022-12-12 22:04:25 +02:00
void DummyAnimation : : nextFrame ( )
2011-12-22 16:05:19 +03:00
{
counter + + ;
if ( counter > howMany )
2022-11-28 16:02:46 +02:00
delete this ;
2011-12-22 16:05:19 +03:00
}
2022-12-22 01:04:58 +02:00
ECreatureAnimType MeleeAttackAnimation : : getUpwardsGroup ( bool multiAttack ) const
2022-12-14 14:21:58 +02:00
{
if ( ! multiAttack )
return ECreatureAnimType : : ATTACK_UP ;
return findValidGroup ( {
ECreatureAnimType : : GROUP_ATTACK_UP ,
ECreatureAnimType : : SPECIAL_UP ,
2022-12-25 17:43:55 +02:00
ECreatureAnimType : : SPECIAL_FRONT , // weird, but required for H3
2022-12-14 14:21:58 +02:00
ECreatureAnimType : : ATTACK_UP
} ) ;
}
2022-12-22 01:04:58 +02:00
ECreatureAnimType MeleeAttackAnimation : : getForwardGroup ( bool multiAttack ) const
2022-12-14 14:21:58 +02:00
{
if ( ! multiAttack )
return ECreatureAnimType : : ATTACK_FRONT ;
return findValidGroup ( {
ECreatureAnimType : : GROUP_ATTACK_FRONT ,
ECreatureAnimType : : SPECIAL_FRONT ,
ECreatureAnimType : : ATTACK_FRONT
} ) ;
}
2022-12-22 01:04:58 +02:00
ECreatureAnimType MeleeAttackAnimation : : getDownwardsGroup ( bool multiAttack ) const
2022-12-14 14:21:58 +02:00
{
if ( ! multiAttack )
return ECreatureAnimType : : ATTACK_DOWN ;
return findValidGroup ( {
ECreatureAnimType : : GROUP_ATTACK_DOWN ,
ECreatureAnimType : : SPECIAL_DOWN ,
2022-12-25 17:43:55 +02:00
ECreatureAnimType : : SPECIAL_FRONT , // weird, but required for H3
2022-12-14 14:21:58 +02:00
ECreatureAnimType : : ATTACK_DOWN
} ) ;
}
2022-12-22 01:04:58 +02:00
ECreatureAnimType MeleeAttackAnimation : : selectGroup ( bool multiAttack )
2011-12-22 16:05:19 +03:00
{
2022-12-22 01:04:58 +02:00
const ECreatureAnimType mutPosToGroup [ ] =
2017-09-08 13:25:12 +02:00
{
2022-12-16 18:34:35 +02:00
getUpwardsGroup ( multiAttack ) ,
getUpwardsGroup ( multiAttack ) ,
getForwardGroup ( multiAttack ) ,
getDownwardsGroup ( multiAttack ) ,
getDownwardsGroup ( multiAttack ) ,
getForwardGroup ( multiAttack )
2017-09-08 13:25:12 +02:00
} ;
2011-12-22 16:05:19 +03:00
2023-04-27 19:43:20 +02:00
int revShiftattacker = ( attackingStack - > unitSide ( ) = = BattleSide : : ATTACKER ? - 1 : 1 ) ;
2011-12-22 16:05:19 +03:00
int mutPos = BattleHex : : mutualPosition ( attackingStackPosBeforeReturn , dest ) ;
if ( mutPos = = - 1 & & attackingStack - > doubleWide ( ) )
{
2022-12-12 22:04:25 +02:00
mutPos = BattleHex : : mutualPosition ( attackingStackPosBeforeReturn + revShiftattacker , defendingStack - > getPosition ( ) ) ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
if ( mutPos = = - 1 & & defendingStack - > doubleWide ( ) )
2011-12-22 16:05:19 +03:00
{
2022-12-12 22:04:25 +02:00
mutPos = BattleHex : : mutualPosition ( attackingStackPosBeforeReturn , defendingStack - > occupiedHex ( ) ) ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
if ( mutPos = = - 1 & & defendingStack - > doubleWide ( ) & & attackingStack - > doubleWide ( ) )
2011-12-22 16:05:19 +03:00
{
2022-12-12 22:04:25 +02:00
mutPos = BattleHex : : mutualPosition ( attackingStackPosBeforeReturn + revShiftattacker , defendingStack - > occupiedHex ( ) ) ;
2011-12-22 16:05:19 +03:00
}
2022-12-14 14:21:58 +02:00
assert ( mutPos > = 0 & & mutPos < = 5 ) ;
2011-12-22 16:05:19 +03:00
2022-12-16 18:34:35 +02:00
return mutPosToGroup [ mutPos ] ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
void MeleeAttackAnimation : : nextFrame ( )
2022-12-10 00:25:11 +02:00
{
size_t currentFrame = stackAnimation ( attackingStack ) - > getCurrentFrame ( ) ;
2022-12-16 18:34:35 +02:00
size_t totalFrames = stackAnimation ( attackingStack ) - > framesInGroup ( getGroup ( ) ) ;
2022-12-10 00:25:11 +02:00
if ( currentFrame * 2 > = totalFrames )
2023-03-19 01:40:31 +02:00
owner . executeAnimationStage ( EAnimationEvents : : HIT ) ;
2022-12-12 22:04:25 +02:00
AttackAnimation : : nextFrame ( ) ;
}
2022-12-10 00:25:11 +02:00
2022-12-14 14:21:58 +02:00
MeleeAttackAnimation : : MeleeAttackAnimation ( BattleInterface & owner , const CStack * attacker , BattleHex _dest , const CStack * _attacked , bool multiAttack )
2022-12-16 18:34:35 +02:00
: AttackAnimation ( owner , attacker , _dest , _attacked )
2014-09-23 16:02:30 +03:00
{
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Created MeleeAttackAnimation for %s " , attacker - > getName ( ) ) ;
2022-12-16 18:34:35 +02:00
setSound ( battle_sound ( getCreature ( ) , attack ) ) ;
setGroup ( selectGroup ( multiAttack ) ) ;
2014-09-23 16:02:30 +03:00
}
2011-12-22 16:05:19 +03:00
2022-12-16 22:07:46 +02:00
StackMoveAnimation : : StackMoveAnimation ( BattleInterface & owner , const CStack * _stack , BattleHex prevHex , BattleHex nextHex ) :
2022-12-12 22:04:25 +02:00
BattleStackAnimation ( owner , _stack ) ,
2022-12-16 22:07:46 +02:00
prevHex ( prevHex ) ,
nextHex ( nextHex )
2022-11-28 22:35:38 +02:00
{
}
2022-12-12 22:04:25 +02:00
bool MovementAnimation : : init ( )
2011-12-22 16:05:19 +03:00
{
2022-12-09 13:10:35 +02:00
assert ( stack ) ;
assert ( ! myAnim - > isDeadOrDying ( ) ) ;
2022-12-18 18:26:43 +02:00
assert ( stackAnimation ( stack ) - > framesInGroup ( ECreatureAnimType : : MOVING ) > 0 ) ;
2011-12-22 16:05:19 +03:00
2022-12-18 18:26:43 +02:00
if ( stackAnimation ( stack ) - > framesInGroup ( ECreatureAnimType : : MOVING ) = = 0 )
2012-09-29 11:35:31 +03:00
{
2022-12-18 18:26:43 +02:00
//no movement, end immediately
2022-11-28 16:02:46 +02:00
delete this ;
2012-09-29 11:35:31 +03:00
return false ;
}
2011-12-22 16:05:19 +03:00
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " CMovementAnimation::init: stack %s moves %d -> %d " , stack - > getName ( ) , prevHex , nextHex ) ;
2022-12-10 00:25:11 +02:00
2011-12-22 16:05:19 +03:00
//reverse unit if necessary
2022-12-16 22:07:46 +02:00
if ( owner . stacksController - > shouldRotate ( stack , prevHex , nextHex ) )
2011-12-22 16:05:19 +03:00
{
2022-12-09 13:10:35 +02:00
// it seems that H3 does NOT plays full rotation animation during movement
2013-07-06 19:10:20 +03:00
// Logical since it takes quite a lot of time
2022-12-16 22:07:46 +02:00
rotateStack ( prevHex ) ;
2011-12-22 16:05:19 +03:00
}
2022-12-08 19:41:02 +02:00
if ( myAnim - > getType ( ) ! = ECreatureAnimType : : MOVING )
2011-12-22 16:05:19 +03:00
{
2022-12-08 19:41:02 +02:00
myAnim - > setType ( ECreatureAnimType : : MOVING ) ;
2011-12-22 16:05:19 +03:00
}
2023-03-20 19:43:37 +02:00
if ( moveSoundHander = = - 1 )
2012-05-15 19:29:40 +03:00
{
2023-04-12 00:52:12 +02:00
moveSoundHander = CCS - > soundh - > playSound ( battle_sound ( stack - > unitType ( ) , move ) , - 1 ) ;
2012-05-15 19:29:40 +03:00
}
2011-12-22 16:05:19 +03:00
2022-12-16 22:07:46 +02:00
Point begPosition = owner . stacksController - > getStackPositionAtHex ( prevHex , stack ) ;
Point endPosition = owner . stacksController - > getStackPositionAtHex ( nextHex , stack ) ;
2011-12-22 16:05:19 +03:00
2023-04-12 00:52:12 +02:00
progressPerSecond = AnimationControls : : getMovementDistance ( stack - > unitType ( ) ) ;
2013-07-06 19:10:20 +03:00
begX = begPosition . x ;
begY = begPosition . y ;
2023-01-04 17:21:40 +02:00
//progress = 0;
2013-07-06 19:10:20 +03:00
distanceX = endPosition . x - begPosition . x ;
distanceY = endPosition . y - begPosition . y ;
2020-11-11 21:43:40 +02:00
if ( stack - > hasBonus ( Selector : : type ( ) ( Bonus : : FLYING ) ) )
2011-12-22 16:05:19 +03:00
{
2020-10-01 10:38:06 +02:00
float distance = static_cast < float > ( sqrt ( distanceX * distanceX + distanceY * distanceY ) ) ;
2023-04-12 00:52:12 +02:00
progressPerSecond = AnimationControls : : getFlightDistance ( stack - > unitType ( ) ) / distance ;
2011-12-22 16:05:19 +03:00
}
return true ;
}
2022-12-12 22:04:25 +02:00
void MovementAnimation : : nextFrame ( )
2011-12-22 16:05:19 +03:00
{
2023-01-27 23:16:02 +02:00
progress + = float ( GH . mainFPSmng - > getElapsedMilliseconds ( ) ) / 1000 * progressPerSecond ;
2013-07-06 19:10:20 +03:00
2011-12-22 16:05:19 +03:00
//moving instructions
2013-07-06 19:10:20 +03:00
myAnim - > pos . x = static_cast < Sint16 > ( begX + distanceX * progress ) ;
myAnim - > pos . y = static_cast < Sint16 > ( begY + distanceY * progress ) ;
2011-12-22 16:05:19 +03:00
2022-12-12 22:04:25 +02:00
BattleAnimation : : nextFrame ( ) ;
2013-07-06 19:10:20 +03:00
if ( progress > = 1.0 )
2011-12-22 16:05:19 +03:00
{
2023-01-04 17:21:40 +02:00
progress - = 1.0 ;
2011-12-22 16:05:19 +03:00
// Sets the position of the creature animation sprites
2022-12-16 22:07:46 +02:00
Point coords = owner . stacksController - > getStackPositionAtHex ( nextHex , stack ) ;
2022-12-15 23:24:03 +02:00
myAnim - > pos . moveTo ( coords ) ;
2011-12-22 16:05:19 +03:00
// true if creature haven't reached the final destination hex
2013-07-06 19:10:20 +03:00
if ( ( curentMoveIndex + 1 ) < destTiles . size ( ) )
2011-12-22 16:05:19 +03:00
{
// update the next hex field which has to be reached by the stack
2013-07-06 19:10:20 +03:00
curentMoveIndex + + ;
2022-12-16 22:07:46 +02:00
prevHex = nextHex ;
nextHex = destTiles [ curentMoveIndex ] ;
2011-12-22 16:05:19 +03:00
2022-11-28 16:02:46 +02:00
// request re-initialization
initialized = false ;
2011-12-22 16:05:19 +03:00
}
else
2022-11-28 16:02:46 +02:00
delete this ;
2011-12-22 16:05:19 +03:00
}
}
2022-12-12 22:04:25 +02:00
MovementAnimation : : ~ MovementAnimation ( )
2011-12-22 16:05:19 +03:00
{
2013-07-06 19:10:20 +03:00
assert ( stack ) ;
2011-12-22 16:05:19 +03:00
2023-03-20 19:43:37 +02:00
if ( moveSoundHander ! = - 1 )
CCS - > soundh - > stopSound ( moveSoundHander ) ;
2011-12-22 16:05:19 +03:00
}
2022-12-16 22:07:46 +02:00
MovementAnimation : : MovementAnimation ( BattleInterface & owner , const CStack * stack , std : : vector < BattleHex > _destTiles , int _distance )
: StackMoveAnimation ( owner , stack , stack - > getPosition ( ) , _destTiles . front ( ) ) ,
2020-10-06 01:27:04 +02:00
destTiles ( _destTiles ) ,
curentMoveIndex ( 0 ) ,
begX ( 0 ) , begY ( 0 ) ,
distanceX ( 0 ) , distanceY ( 0 ) ,
2023-01-27 23:16:02 +02:00
progressPerSecond ( 0.0 ) ,
2023-03-20 19:43:37 +02:00
moveSoundHander ( - 1 ) ,
2022-11-28 22:35:38 +02:00
progress ( 0.0 )
2011-12-22 16:05:19 +03:00
{
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Created MovementAnimation for %s " , stack - > getName ( ) ) ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
MovementEndAnimation : : MovementEndAnimation ( BattleInterface & owner , const CStack * _stack , BattleHex destTile )
2022-12-16 22:07:46 +02:00
: StackMoveAnimation ( owner , _stack , destTile , destTile )
2014-09-23 16:02:30 +03:00
{
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Created MovementEndAnimation for %s " , stack - > getName ( ) ) ;
2014-09-23 16:02:30 +03:00
}
2011-12-22 16:05:19 +03:00
2022-12-12 22:04:25 +02:00
bool MovementEndAnimation : : init ( )
2011-12-22 16:05:19 +03:00
{
2022-12-09 13:10:35 +02:00
assert ( stack ) ;
assert ( ! myAnim - > isDeadOrDying ( ) ) ;
2011-12-22 16:05:19 +03:00
2022-12-09 13:10:35 +02:00
if ( ! stack | | myAnim - > isDeadOrDying ( ) )
2011-12-22 16:05:19 +03:00
{
2022-11-28 16:02:46 +02:00
delete this ;
2011-12-22 16:05:19 +03:00
return false ;
}
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " CMovementEndAnimation::init: stack %s " , stack - > getName ( ) ) ;
2022-12-18 22:32:07 +02:00
myAnim - > pos . moveTo ( owner . stacksController - > getStackPositionAtHex ( nextHex , stack ) ) ;
2022-12-10 00:25:11 +02:00
2023-04-12 00:52:12 +02:00
CCS - > soundh - > playSound ( battle_sound ( stack - > unitType ( ) , endMoving ) ) ;
2011-12-22 16:05:19 +03:00
2022-12-09 13:10:35 +02:00
if ( ! myAnim - > framesInGroup ( ECreatureAnimType : : MOVE_END ) )
{
delete this ;
return false ;
}
2011-12-22 16:05:19 +03:00
2022-12-10 00:25:11 +02:00
2022-12-09 13:10:35 +02:00
myAnim - > setType ( ECreatureAnimType : : MOVE_END ) ;
2022-11-28 16:02:46 +02:00
myAnim - > onAnimationReset + = [ & ] ( ) { delete this ; } ;
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
return true ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
MovementEndAnimation : : ~ MovementEndAnimation ( )
2011-12-22 16:05:19 +03:00
{
2022-12-08 19:41:02 +02:00
if ( myAnim - > getType ( ) ! = ECreatureAnimType : : DEAD )
myAnim - > setType ( ECreatureAnimType : : HOLDING ) ; //resetting to default
2011-12-22 16:05:19 +03:00
CCS - > curh - > show ( ) ;
}
2022-12-12 22:04:25 +02:00
MovementStartAnimation : : MovementStartAnimation ( BattleInterface & owner , const CStack * _stack )
2022-12-16 22:07:46 +02:00
: StackMoveAnimation ( owner , _stack , _stack - > getPosition ( ) , _stack - > getPosition ( ) )
2014-09-23 16:02:30 +03:00
{
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Created MovementStartAnimation for %s " , stack - > getName ( ) ) ;
2014-09-23 16:02:30 +03:00
}
2011-12-22 16:05:19 +03:00
2022-12-12 22:04:25 +02:00
bool MovementStartAnimation : : init ( )
2011-12-22 16:05:19 +03:00
{
2022-12-09 13:10:35 +02:00
assert ( stack ) ;
assert ( ! myAnim - > isDeadOrDying ( ) ) ;
2011-12-22 16:05:19 +03:00
2022-11-28 22:35:38 +02:00
if ( ! stack | | myAnim - > isDeadOrDying ( ) )
2011-12-22 16:05:19 +03:00
{
2022-11-28 16:02:46 +02:00
delete this ;
2011-12-22 16:05:19 +03:00
return false ;
}
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " CMovementStartAnimation::init: stack %s " , stack - > getName ( ) ) ;
2023-04-12 00:52:12 +02:00
CCS - > soundh - > playSound ( battle_sound ( stack - > unitType ( ) , startMoving ) ) ;
2022-12-09 13:10:35 +02:00
if ( ! myAnim - > framesInGroup ( ECreatureAnimType : : MOVE_START ) )
{
delete this ;
return false ;
}
2022-12-08 19:41:02 +02:00
myAnim - > setType ( ECreatureAnimType : : MOVE_START ) ;
2022-11-28 16:02:46 +02:00
myAnim - > onAnimationReset + = [ & ] ( ) { delete this ; } ;
2011-12-22 16:05:19 +03:00
return true ;
}
2022-12-12 22:04:25 +02:00
ReverseAnimation : : ReverseAnimation ( BattleInterface & owner , const CStack * stack , BattleHex dest )
2022-12-16 22:07:46 +02:00
: StackMoveAnimation ( owner , stack , dest , dest )
2014-09-23 16:02:30 +03:00
{
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Created ReverseAnimation for %s " , stack - > getName ( ) ) ;
2014-09-23 16:02:30 +03:00
}
2011-12-22 16:05:19 +03:00
2022-12-12 22:04:25 +02:00
bool ReverseAnimation : : init ( )
2011-12-22 16:05:19 +03:00
{
2022-12-11 12:29:11 +02:00
assert ( myAnim ) ;
assert ( ! myAnim - > isDeadOrDying ( ) ) ;
2022-11-28 22:35:38 +02:00
if ( myAnim = = nullptr | | myAnim - > isDeadOrDying ( ) )
2011-12-22 16:05:19 +03:00
{
2022-11-28 16:02:46 +02:00
delete this ;
2011-12-22 16:05:19 +03:00
return false ; //there is no such creature
}
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " CReverseAnimation::init: stack %s " , stack - > getName ( ) ) ;
2022-12-08 19:41:02 +02:00
if ( myAnim - > framesInGroup ( ECreatureAnimType : : TURN_L ) )
2011-12-22 16:05:19 +03:00
{
2022-12-10 00:25:11 +02:00
myAnim - > playOnce ( ECreatureAnimType : : TURN_L ) ;
2022-12-12 22:04:25 +02:00
myAnim - > onAnimationReset + = std : : bind ( & ReverseAnimation : : setupSecondPart , this ) ;
2011-12-22 16:05:19 +03:00
}
2013-07-06 19:10:20 +03:00
else
2011-12-22 16:05:19 +03:00
{
2013-07-06 19:10:20 +03:00
setupSecondPart ( ) ;
2011-12-22 16:05:19 +03:00
}
2013-07-06 19:10:20 +03:00
return true ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
void BattleStackAnimation : : rotateStack ( BattleHex hex )
2011-12-22 16:05:19 +03:00
{
2022-11-20 19:11:34 +02:00
setStackFacingRight ( stack , ! stackFacingRight ( stack ) ) ;
2012-09-16 17:36:31 +03:00
2022-12-15 23:24:03 +02:00
stackAnimation ( stack ) - > pos . moveTo ( owner . stacksController - > getStackPositionAtHex ( hex , stack ) ) ;
2013-07-06 19:10:20 +03:00
}
2022-12-12 22:04:25 +02:00
void ReverseAnimation : : setupSecondPart ( )
2013-07-06 19:10:20 +03:00
{
2022-12-11 12:29:11 +02:00
assert ( stack ) ;
2013-07-06 19:10:20 +03:00
if ( ! stack )
{
2022-11-28 16:02:46 +02:00
delete this ;
2013-07-06 19:10:20 +03:00
return ;
}
2011-12-22 16:05:19 +03:00
2022-12-16 22:07:46 +02:00
rotateStack ( nextHex ) ;
2011-12-22 16:05:19 +03:00
2022-12-08 19:41:02 +02:00
if ( myAnim - > framesInGroup ( ECreatureAnimType : : TURN_R ) )
2013-07-06 19:10:20 +03:00
{
2022-12-10 00:25:11 +02:00
myAnim - > playOnce ( ECreatureAnimType : : TURN_R ) ;
2022-11-28 16:02:46 +02:00
myAnim - > onAnimationReset + = [ & ] ( ) { delete this ; } ;
2013-07-06 19:10:20 +03:00
}
2011-12-22 16:05:19 +03:00
else
2022-11-28 16:02:46 +02:00
delete this ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
ResurrectionAnimation : : ResurrectionAnimation ( BattleInterface & owner , const CStack * _stack ) :
2022-12-16 18:34:35 +02:00
StackActionAnimation ( owner , _stack )
2022-12-08 20:43:51 +02:00
{
2022-12-16 18:34:35 +02:00
setGroup ( ECreatureAnimType : : RESURRECTION ) ;
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Created ResurrectionAnimation for %s " , stack - > getName ( ) ) ;
2022-12-14 12:04:37 +02:00
}
2022-12-18 18:26:43 +02:00
bool ColorTransformAnimation : : init ( )
{
return true ;
}
2022-12-15 23:24:03 +02:00
void ColorTransformAnimation : : nextFrame ( )
2022-12-14 12:04:37 +02:00
{
float elapsed = GH . mainFPSmng - > getElapsedMilliseconds ( ) / 1000.f ;
float fullTime = AnimationControls : : getFadeInDuration ( ) ;
float delta = elapsed / fullTime ;
2022-12-15 23:24:03 +02:00
totalProgress + = delta ;
2022-12-14 12:04:37 +02:00
2022-12-15 23:24:03 +02:00
size_t index = 0 ;
2022-12-14 14:21:58 +02:00
2022-12-15 23:24:03 +02:00
while ( index < timePoints . size ( ) & & timePoints [ index ] < totalProgress )
+ + index ;
2022-12-14 14:21:58 +02:00
2022-12-15 23:24:03 +02:00
if ( index = = timePoints . size ( ) )
{
//end of animation. Apply ColorShifter using final values and die
const auto & shifter = steps [ index - 1 ] ;
owner . stacksController - > setStackColorFilter ( shifter , stack , spell , false ) ;
2022-12-14 12:04:37 +02:00
delete this ;
2022-12-15 23:24:03 +02:00
return ;
}
assert ( index ! = 0 ) ;
const auto & prevShifter = steps [ index - 1 ] ;
const auto & nextShifter = steps [ index ] ;
float prevPoint = timePoints [ index - 1 ] ;
float nextPoint = timePoints [ index ] ;
float localProgress = totalProgress - prevPoint ;
float stepDuration = ( nextPoint - prevPoint ) ;
float factor = localProgress / stepDuration ;
auto shifter = ColorFilter : : genInterpolated ( prevShifter , nextShifter , factor ) ;
owner . stacksController - > setStackColorFilter ( shifter , stack , spell , true ) ;
2022-12-14 12:04:37 +02:00
}
2022-12-21 23:29:56 +02:00
ColorTransformAnimation : : ColorTransformAnimation ( BattleInterface & owner , const CStack * _stack , const std : : string & colorFilterName , const CSpell * spell ) :
2022-12-18 18:26:43 +02:00
BattleStackAnimation ( owner , _stack ) ,
2022-12-15 23:24:03 +02:00
spell ( spell ) ,
totalProgress ( 0.f )
{
2022-12-21 23:29:56 +02:00
auto effect = owner . effectsController - > getMuxerEffect ( colorFilterName ) ;
steps = effect . filters ;
timePoints = effect . timePoints ;
2022-12-15 23:24:03 +02:00
2022-12-21 23:29:56 +02:00
assert ( ! steps . empty ( ) & & steps . size ( ) = = timePoints . size ( ) ) ;
2022-12-14 12:04:37 +02:00
2022-12-21 23:29:56 +02:00
logAnim - > debug ( " Created ColorTransformAnimation for %s " , stack - > getName ( ) ) ;
2022-12-18 18:26:43 +02:00
}
2022-12-12 22:04:25 +02:00
RangedAttackAnimation : : RangedAttackAnimation ( BattleInterface & owner_ , const CStack * attacker , BattleHex dest_ , const CStack * defender )
: AttackAnimation ( owner_ , attacker , dest_ , defender ) ,
2022-12-01 22:06:42 +02:00
projectileEmitted ( false )
2017-09-08 13:25:12 +02:00
{
2022-12-16 18:34:35 +02:00
setSound ( battle_sound ( getCreature ( ) , shoot ) ) ;
2022-12-12 22:04:25 +02:00
}
bool RangedAttackAnimation : : init ( )
2011-12-22 16:05:19 +03:00
{
2022-11-25 16:32:23 +02:00
setAnimationGroup ( ) ;
2022-11-27 17:24:45 +02:00
initializeProjectile ( ) ;
2022-12-16 18:34:35 +02:00
return AttackAnimation : : init ( ) ;
2022-11-25 16:32:23 +02:00
}
2022-12-12 22:04:25 +02:00
void RangedAttackAnimation : : setAnimationGroup ( )
2022-11-25 16:32:23 +02:00
{
Point shooterPos = stackAnimation ( attackingStack ) - > pos . topLeft ( ) ;
2022-12-12 22:04:25 +02:00
Point shotTarget = owner . stacksController - > getStackPositionAtHex ( dest , defendingStack ) ;
2022-11-25 16:32:23 +02:00
2013-04-04 21:20:25 +03:00
//maximal angle in radians between straight horizontal line and shooting line for which shot is considered to be straight (absoulte value)
static const double straightAngle = 0.2 ;
2011-12-22 16:05:19 +03:00
2022-11-27 20:01:52 +02:00
double projectileAngle = - atan2 ( shotTarget . y - shooterPos . y , std : : abs ( shotTarget . x - shooterPos . x ) ) ;
2021-01-17 14:02:58 +02:00
2022-11-25 16:32:23 +02:00
// Calculate projectile start position. Offsets are read out of the CRANIM.TXT.
if ( projectileAngle > straightAngle )
2022-12-16 18:34:35 +02:00
setGroup ( getUpwardsGroup ( ) ) ;
2022-11-25 16:32:23 +02:00
else if ( projectileAngle < - straightAngle )
2022-12-16 18:34:35 +02:00
setGroup ( getDownwardsGroup ( ) ) ;
2022-11-25 16:32:23 +02:00
else
2022-12-16 18:34:35 +02:00
setGroup ( getForwardGroup ( ) ) ;
2022-11-25 16:32:23 +02:00
}
2011-12-22 16:05:19 +03:00
2022-12-12 22:04:25 +02:00
void RangedAttackAnimation : : initializeProjectile ( )
2022-11-25 16:32:23 +02:00
{
2022-11-27 20:01:52 +02:00
const CCreature * shooterInfo = getCreature ( ) ;
2022-12-12 22:04:25 +02:00
Point shotTarget = owner . stacksController - > getStackPositionAtHex ( dest , defendingStack ) + Point ( 225 , 225 ) ;
2022-11-25 16:32:23 +02:00
Point shotOrigin = stackAnimation ( attackingStack ) - > pos . topLeft ( ) + Point ( 222 , 265 ) ;
int multiplier = stackFacingRight ( attackingStack ) ? 1 : - 1 ;
2013-04-04 16:18:38 +03:00
2022-12-16 18:34:35 +02:00
if ( getGroup ( ) = = getUpwardsGroup ( ) )
2022-11-17 13:21:03 +02:00
{
2022-11-25 16:32:23 +02:00
shotOrigin . x + = ( - 25 + shooterInfo - > animation . upperRightMissleOffsetX ) * multiplier ;
shotOrigin . y + = shooterInfo - > animation . upperRightMissleOffsetY ;
2022-11-17 13:21:03 +02:00
}
2022-12-16 18:34:35 +02:00
else if ( getGroup ( ) = = getDownwardsGroup ( ) )
2013-04-04 21:20:25 +03:00
{
2022-11-25 16:32:23 +02:00
shotOrigin . x + = ( - 25 + shooterInfo - > animation . lowerRightMissleOffsetX ) * multiplier ;
shotOrigin . y + = shooterInfo - > animation . lowerRightMissleOffsetY ;
2013-04-04 21:20:25 +03:00
}
2022-12-16 18:34:35 +02:00
else if ( getGroup ( ) = = getForwardGroup ( ) )
2013-04-04 21:20:25 +03:00
{
2022-11-25 16:32:23 +02:00
shotOrigin . x + = ( - 25 + shooterInfo - > animation . rightMissleOffsetX ) * multiplier ;
shotOrigin . y + = shooterInfo - > animation . rightMissleOffsetY ;
2013-04-04 21:20:25 +03:00
}
else
{
2022-11-25 16:32:23 +02:00
assert ( 0 ) ;
2022-11-15 21:42:16 +02:00
}
2013-04-04 16:18:38 +03:00
2022-12-01 22:06:42 +02:00
createProjectile ( shotOrigin , shotTarget ) ;
2022-11-25 16:32:23 +02:00
}
2011-12-22 16:05:19 +03:00
2022-12-12 22:04:25 +02:00
void RangedAttackAnimation : : emitProjectile ( )
2022-11-25 16:32:23 +02:00
{
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Ranged attack projectile emitted " ) ;
2022-12-13 13:58:16 +02:00
owner . projectilesController - > emitStackProjectile ( attackingStack ) ;
2022-11-25 16:32:23 +02:00
projectileEmitted = true ;
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
void RangedAttackAnimation : : nextFrame ( )
2011-12-22 16:05:19 +03:00
{
2022-11-27 20:01:52 +02:00
// animation should be paused if there is an active projectile
if ( projectileEmitted )
{
2022-12-15 23:24:03 +02:00
if ( ! owner . projectilesController - > hasActiveProjectile ( attackingStack , false ) )
2023-03-19 01:40:31 +02:00
owner . executeAnimationStage ( EAnimationEvents : : HIT ) ;
2022-11-27 20:01:52 +02:00
}
2023-03-20 17:48:52 +02:00
bool stackHasProjectile = owner . projectilesController - > hasActiveProjectile ( stack , true ) ;
if ( ! projectileEmitted | | stackHasProjectile )
stackAnimation ( attackingStack ) - > playUntil ( getAttackClimaxFrame ( ) ) ;
else
stackAnimation ( attackingStack ) - > playUntil ( static_cast < size_t > ( - 1 ) ) ;
2022-12-12 22:04:25 +02:00
AttackAnimation : : nextFrame ( ) ;
2022-11-27 20:01:52 +02:00
2022-11-25 16:32:23 +02:00
if ( ! projectileEmitted )
2022-11-20 19:11:34 +02:00
{
2022-11-27 17:24:45 +02:00
// emit projectile once animation playback reached "climax" frame
2022-12-06 14:12:13 +02:00
if ( stackAnimation ( attackingStack ) - > getCurrentFrame ( ) > = getAttackClimaxFrame ( ) )
2022-11-20 19:11:34 +02:00
{
2022-11-25 16:32:23 +02:00
emitProjectile ( ) ;
2022-11-20 19:11:34 +02:00
return ;
}
}
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
RangedAttackAnimation : : ~ RangedAttackAnimation ( )
2011-12-22 16:05:19 +03:00
{
2022-12-15 23:24:03 +02:00
assert ( ! owner . projectilesController - > hasActiveProjectile ( attackingStack , false ) ) ;
2022-11-27 20:01:52 +02:00
assert ( projectileEmitted ) ;
2022-11-20 19:11:34 +02:00
// FIXME: is this possible? Animation is over but we're yet to fire projectile?
2022-11-25 16:32:23 +02:00
if ( ! projectileEmitted )
{
2022-11-27 17:24:45 +02:00
logAnim - > warn ( " Shooting animation has finished but projectile was not emitted! Emitting it now... " ) ;
2022-11-25 16:32:23 +02:00
emitProjectile ( ) ;
}
2011-12-22 16:05:19 +03:00
}
2022-12-12 22:04:25 +02:00
ShootingAnimation : : ShootingAnimation ( BattleInterface & owner , const CStack * attacker , BattleHex _dest , const CStack * _attacked )
: RangedAttackAnimation ( owner , attacker , _dest , _attacked )
2017-09-08 13:25:12 +02:00
{
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " Created ShootingAnimation for %s " , stack - > getName ( ) ) ;
2017-09-08 13:25:12 +02:00
}
2022-12-12 22:04:25 +02:00
void ShootingAnimation : : createProjectile ( const Point & from , const Point & dest ) const
2017-09-08 13:25:12 +02:00
{
2022-12-13 13:58:16 +02:00
owner . projectilesController - > createProjectile ( attackingStack , from , dest ) ;
2022-12-01 22:06:42 +02:00
}
2017-09-08 13:25:12 +02:00
2022-12-12 22:04:25 +02:00
uint32_t ShootingAnimation : : getAttackClimaxFrame ( ) const
2022-12-06 14:12:13 +02:00
{
const CCreature * shooterInfo = getCreature ( ) ;
2023-03-28 16:04:18 +02:00
uint32_t maxFrames = stackAnimation ( attackingStack ) - > framesInGroup ( getGroup ( ) ) ;
uint32_t climaxFrame = shooterInfo - > animation . attackClimaxFrame ;
2023-04-11 00:00:46 +02:00
uint32_t selectedFrame = std : : clamp < int > ( shooterInfo - > animation . attackClimaxFrame , 1 , maxFrames ) ;
2023-03-28 16:04:18 +02:00
if ( climaxFrame ! = selectedFrame )
logGlobal - > warn ( " Shooter %s has ranged attack climax frame set to %d, but only %d available! " , shooterInfo - > getNamePluralTranslated ( ) , climaxFrame , maxFrames ) ;
return selectedFrame - 1 ; // H3 counts frames from 1
2022-12-06 14:12:13 +02:00
}
2022-12-22 01:04:58 +02:00
ECreatureAnimType ShootingAnimation : : getUpwardsGroup ( ) const
2022-12-01 22:06:42 +02:00
{
2022-12-08 19:41:02 +02:00
return ECreatureAnimType : : SHOOT_UP ;
2022-12-01 22:06:42 +02:00
}
2017-09-08 13:25:12 +02:00
2022-12-22 01:04:58 +02:00
ECreatureAnimType ShootingAnimation : : getForwardGroup ( ) const
2022-12-01 22:06:42 +02:00
{
2022-12-08 19:41:02 +02:00
return ECreatureAnimType : : SHOOT_FRONT ;
2022-12-01 22:06:42 +02:00
}
2017-09-08 13:25:12 +02:00
2022-12-22 01:04:58 +02:00
ECreatureAnimType ShootingAnimation : : getDownwardsGroup ( ) const
2022-12-01 22:06:42 +02:00
{
2022-12-08 19:41:02 +02:00
return ECreatureAnimType : : SHOOT_DOWN ;
2022-12-01 22:06:42 +02:00
}
2017-09-08 13:25:12 +02:00
2022-12-12 22:04:25 +02:00
CatapultAnimation : : CatapultAnimation ( BattleInterface & owner , const CStack * attacker , BattleHex _dest , const CStack * _attacked , int _catapultDmg )
: ShootingAnimation ( owner , attacker , _dest , _attacked ) ,
2022-12-01 22:06:42 +02:00
catapultDamage ( _catapultDmg ) ,
explosionEmitted ( false )
{
logAnim - > debug ( " Created shooting anim for %s " , stack - > getName ( ) ) ;
}
2017-09-08 13:25:12 +02:00
2022-12-12 22:04:25 +02:00
void CatapultAnimation : : nextFrame ( )
2022-12-01 22:06:42 +02:00
{
2022-12-12 22:04:25 +02:00
ShootingAnimation : : nextFrame ( ) ;
2017-09-08 13:25:12 +02:00
2022-12-01 22:06:42 +02:00
if ( explosionEmitted )
return ;
2017-09-08 13:25:12 +02:00
2022-12-01 22:06:42 +02:00
if ( ! projectileEmitted )
return ;
2017-09-08 13:25:12 +02:00
2022-12-15 23:24:03 +02:00
if ( owner . projectilesController - > hasActiveProjectile ( attackingStack , false ) )
2022-12-01 22:06:42 +02:00
return ;
2017-09-08 13:25:12 +02:00
2022-12-01 22:06:42 +02:00
explosionEmitted = true ;
2022-12-12 22:04:25 +02:00
Point shotTarget = owner . stacksController - > getStackPositionAtHex ( dest , defendingStack ) + Point ( 225 , 225 ) - Point ( 126 , 105 ) ;
2017-09-08 13:25:12 +02:00
2022-12-25 21:35:13 +02:00
std : : string soundFilename = ( catapultDamage > 0 ) ? " WALLHIT " : " WALLMISS " ;
std : : string effectFilename = ( catapultDamage > 0 ) ? " SGEXPL " : " CSGRCK " ;
CCS - > soundh - > playSound ( soundFilename ) ;
2022-12-25 21:39:55 +02:00
owner . stacksController - > addNewAnim ( new EffectAnimation ( owner , effectFilename , shotTarget ) ) ;
2022-12-01 22:06:42 +02:00
}
2017-09-08 13:25:12 +02:00
2022-12-12 22:04:25 +02:00
void CatapultAnimation : : createProjectile ( const Point & from , const Point & dest ) const
2022-12-01 22:06:42 +02:00
{
2022-12-13 13:58:16 +02:00
owner . projectilesController - > createCatapultProjectile ( attackingStack , from , dest ) ;
2022-12-01 22:06:42 +02:00
}
2017-09-08 13:25:12 +02:00
2023-01-04 21:26:13 +02:00
CastAnimation : : CastAnimation ( BattleInterface & owner_ , const CStack * attacker , BattleHex dest , const CStack * defender , const CSpell * spell )
: RangedAttackAnimation ( owner_ , attacker , dest , defender ) ,
2022-12-01 22:06:42 +02:00
spell ( spell )
{
2023-01-04 21:26:13 +02:00
if ( ! dest . isValid ( ) )
{
assert ( spell - > animationInfo . projectile . empty ( ) ) ;
2017-09-08 13:25:12 +02:00
2023-01-04 21:26:13 +02:00
if ( defender )
dest = defender - > getPosition ( ) ;
else
dest = attacker - > getPosition ( ) ;
}
2022-12-01 22:06:42 +02:00
}
2017-09-08 13:25:12 +02:00
2022-12-22 01:04:58 +02:00
ECreatureAnimType CastAnimation : : getUpwardsGroup ( ) const
2017-09-08 13:25:12 +02:00
{
2022-12-01 22:06:42 +02:00
return findValidGroup ( {
2022-12-08 19:41:02 +02:00
ECreatureAnimType : : CAST_UP ,
2022-12-14 14:21:58 +02:00
ECreatureAnimType : : SPECIAL_UP ,
2022-12-25 17:43:55 +02:00
ECreatureAnimType : : SPECIAL_FRONT , // weird, but required for H3
2022-12-08 19:41:02 +02:00
ECreatureAnimType : : SHOOT_UP ,
ECreatureAnimType : : ATTACK_UP
2022-12-01 22:06:42 +02:00
} ) ;
}
2017-09-08 13:25:12 +02:00
2022-12-22 01:04:58 +02:00
ECreatureAnimType CastAnimation : : getForwardGroup ( ) const
2022-12-01 22:06:42 +02:00
{
return findValidGroup ( {
2022-12-08 19:41:02 +02:00
ECreatureAnimType : : CAST_FRONT ,
2022-12-14 14:21:58 +02:00
ECreatureAnimType : : SPECIAL_FRONT ,
2022-12-08 19:41:02 +02:00
ECreatureAnimType : : SHOOT_FRONT ,
ECreatureAnimType : : ATTACK_FRONT
2022-12-01 22:06:42 +02:00
} ) ;
}
2017-09-08 13:25:12 +02:00
2022-12-22 01:04:58 +02:00
ECreatureAnimType CastAnimation : : getDownwardsGroup ( ) const
2022-12-01 22:06:42 +02:00
{
return findValidGroup ( {
2022-12-08 19:41:02 +02:00
ECreatureAnimType : : CAST_DOWN ,
2022-12-14 14:21:58 +02:00
ECreatureAnimType : : SPECIAL_DOWN ,
2022-12-25 17:43:55 +02:00
ECreatureAnimType : : SPECIAL_FRONT , // weird, but required for H3
2022-12-08 19:41:02 +02:00
ECreatureAnimType : : SHOOT_DOWN ,
ECreatureAnimType : : ATTACK_DOWN
2022-12-01 22:06:42 +02:00
} ) ;
2017-09-08 13:25:12 +02:00
}
2022-12-12 22:04:25 +02:00
void CastAnimation : : createProjectile ( const Point & from , const Point & dest ) const
2014-09-23 17:30:36 +03:00
{
2022-12-01 23:40:03 +02:00
if ( ! spell - > animationInfo . projectile . empty ( ) )
2022-12-13 13:58:16 +02:00
owner . projectilesController - > createSpellProjectile ( attackingStack , from , dest , spell ) ;
2022-12-01 22:06:42 +02:00
}
2017-07-20 06:08:49 +02:00
2022-12-12 22:04:25 +02:00
uint32_t CastAnimation : : getAttackClimaxFrame ( ) const
2022-12-06 14:12:13 +02:00
{
2022-12-14 12:04:37 +02:00
//TODO: allow defining this parameter in config file, separately from attackClimaxFrame of missile attacks
2022-12-16 18:34:35 +02:00
uint32_t maxFrames = stackAnimation ( attackingStack ) - > framesInGroup ( getGroup ( ) ) ;
2022-12-06 14:12:13 +02:00
2022-12-16 18:34:35 +02:00
return maxFrames / 2 ;
2022-12-06 14:12:13 +02:00
}
2023-03-26 02:48:11 +02:00
EffectAnimation : : EffectAnimation ( BattleInterface & owner , std : : string animationName , int effects , bool reversed ) :
2022-12-12 22:04:25 +02:00
BattleAnimation ( owner ) ,
2022-12-01 22:06:42 +02:00
animation ( std : : make_shared < CAnimation > ( animationName ) ) ,
effectFlags ( effects ) ,
2023-03-26 02:48:11 +02:00
effectFinished ( false ) ,
reversed ( reversed )
2022-12-01 22:06:42 +02:00
{
2022-12-16 22:37:44 +02:00
logAnim - > debug ( " CPointEffectAnimation::init: effect %s " , animationName ) ;
2014-09-23 17:30:36 +03:00
}
2011-12-22 16:05:19 +03:00
2023-03-26 02:48:11 +02:00
EffectAnimation : : EffectAnimation ( BattleInterface & owner , std : : string animationName , std : : vector < BattleHex > hex , int effects , bool reversed ) :
EffectAnimation ( owner , animationName , effects , reversed )
2017-07-20 06:08:49 +02:00
{
2022-12-02 01:55:09 +02:00
battlehexes = hex ;
2017-07-20 06:08:49 +02:00
}
2023-03-26 02:48:11 +02:00
EffectAnimation : : EffectAnimation ( BattleInterface & owner , std : : string animationName , BattleHex hex , int effects , bool reversed ) :
EffectAnimation ( owner , animationName , effects , reversed )
2022-12-01 22:06:42 +02:00
{
2022-12-02 01:55:09 +02:00
assert ( hex . isValid ( ) ) ;
battlehexes . push_back ( hex ) ;
2022-12-01 22:06:42 +02:00
}
2017-07-20 06:08:49 +02:00
2023-03-26 02:48:11 +02:00
EffectAnimation : : EffectAnimation ( BattleInterface & owner , std : : string animationName , std : : vector < Point > pos , int effects , bool reversed ) :
EffectAnimation ( owner , animationName , effects , reversed )
2022-12-01 22:06:42 +02:00
{
positions = pos ;
}
2023-03-26 02:48:11 +02:00
EffectAnimation : : EffectAnimation ( BattleInterface & owner , std : : string animationName , Point pos , int effects , bool reversed ) :
EffectAnimation ( owner , animationName , effects , reversed )
2014-09-23 17:30:36 +03:00
{
2022-12-01 22:06:42 +02:00
positions . push_back ( pos ) ;
2014-11-27 15:51:16 +02:00
}
2023-03-26 02:48:11 +02:00
EffectAnimation : : EffectAnimation ( BattleInterface & owner , std : : string animationName , Point pos , BattleHex hex , int effects , bool reversed ) :
EffectAnimation ( owner , animationName , effects , reversed )
2022-12-02 01:55:09 +02:00
{
assert ( hex . isValid ( ) ) ;
battlehexes . push_back ( hex ) ;
positions . push_back ( pos ) ;
}
2022-12-25 21:39:55 +02:00
bool EffectAnimation : : init ( )
2011-12-22 16:05:19 +03:00
{
2017-09-05 16:21:44 +02:00
animation - > preload ( ) ;
2018-03-30 13:02:04 +02:00
auto first = animation - > getImage ( 0 , 0 , true ) ;
2017-09-05 16:21:44 +02:00
if ( ! first )
2014-11-27 15:51:16 +02:00
{
2022-11-28 16:02:46 +02:00
delete this ;
2017-09-05 16:21:44 +02:00
return false ;
}
2011-12-22 16:05:19 +03:00
2023-03-26 02:48:11 +02:00
for ( size_t i = 0 ; i < animation - > size ( size_t ( BattleEffect : : AnimType : : DEFAULT ) ) ; + + i )
{
size_t current = animation - > size ( size_t ( BattleEffect : : AnimType : : DEFAULT ) ) - 1 - i ;
animation - > duplicateImage ( size_t ( BattleEffect : : AnimType : : DEFAULT ) , current , size_t ( BattleEffect : : AnimType : : REVERSE ) ) ;
}
2022-12-02 01:55:09 +02:00
if ( screenFill ( ) )
2017-09-05 16:21:44 +02:00
{
2022-12-21 17:02:53 +02:00
for ( int i = 0 ; i * first - > width ( ) < owner . fieldController - > pos . w ; + + i )
for ( int j = 0 ; j * first - > height ( ) < owner . fieldController - > pos . h ; + + j )
2023-01-05 14:16:01 +02:00
positions . push_back ( Point ( i * first - > width ( ) , j * first - > height ( ) ) ) ;
2022-12-01 22:06:42 +02:00
}
2017-09-05 16:21:44 +02:00
2022-12-01 22:06:42 +02:00
BattleEffect be ;
be . effectID = ID ;
be . animation = animation ;
be . currentFrame = 0 ;
2023-03-26 02:48:11 +02:00
be . type = reversed ? BattleEffect : : AnimType : : REVERSE : BattleEffect : : AnimType : : DEFAULT ;
2014-11-27 15:51:16 +02:00
2022-12-02 01:55:09 +02:00
for ( size_t i = 0 ; i < std : : max ( battlehexes . size ( ) , positions . size ( ) ) ; + + i )
2022-12-01 22:06:42 +02:00
{
2022-12-02 01:55:09 +02:00
bool hasTile = i < battlehexes . size ( ) ;
bool hasPosition = i < positions . size ( ) ;
2011-12-22 16:05:19 +03:00
2022-12-02 01:55:09 +02:00
if ( hasTile & & ! forceOnTop ( ) )
2023-01-05 14:16:01 +02:00
be . tile = battlehexes [ i ] ;
2022-12-02 01:55:09 +02:00
else
2023-01-05 14:16:01 +02:00
be . tile = BattleHex : : INVALID ;
2016-11-27 16:48:18 +02:00
2022-12-02 01:55:09 +02:00
if ( hasPosition )
{
2023-01-05 14:16:01 +02:00
be . pos . x = positions [ i ] . x ;
be . pos . y = positions [ i ] . y ;
2022-12-02 01:55:09 +02:00
}
else
{
2023-04-01 01:58:40 +02:00
const auto * destStack = owner . getCurrentPlayerInterface ( ) - > cb - > battleGetUnitByPos ( battlehexes [ i ] , false ) ;
2023-01-05 14:16:01 +02:00
Rect tilePos = owner . fieldController - > hexPositionLocal ( battlehexes [ i ] ) ;
2011-12-22 16:05:19 +03:00
2023-01-05 14:16:01 +02:00
be . pos . x = tilePos . x + tilePos . w / 2 - first - > width ( ) / 2 ;
2013-07-10 13:45:51 +03:00
2022-12-02 01:55:09 +02:00
if ( destStack & & destStack - > doubleWide ( ) ) // Correction for 2-hex creatures.
2023-04-01 01:58:40 +02:00
be . pos . x + = ( destStack - > unitSide ( ) = = BattleSide : : ATTACKER ? - 1 : 1 ) * tilePos . w / 2 ;
2014-11-27 15:51:16 +02:00
2022-12-02 01:55:09 +02:00
if ( alignToBottom ( ) )
2023-01-05 14:16:01 +02:00
be . pos . y = tilePos . y + tilePos . h - first - > height ( ) ;
2022-12-02 01:55:09 +02:00
else
2023-01-05 14:16:01 +02:00
be . pos . y = tilePos . y - first - > height ( ) / 2 ;
2022-12-02 01:55:09 +02:00
}
2022-12-13 13:58:16 +02:00
owner . effectsController - > battleEffects . push_back ( be ) ;
2011-12-22 16:05:19 +03:00
}
return true ;
}
2022-12-25 21:39:55 +02:00
void EffectAnimation : : nextFrame ( )
2022-12-01 22:06:42 +02:00
{
playEffect ( ) ;
2022-12-25 21:35:13 +02:00
if ( effectFinished )
2022-12-02 01:55:09 +02:00
{
//remove visual effect itself only if sound has finished as well - necessary for obstacles like force field
clearEffect ( ) ;
2022-12-01 22:06:42 +02:00
delete this ;
2022-12-02 01:55:09 +02:00
}
2022-12-01 22:06:42 +02:00
}
2022-12-25 21:39:55 +02:00
bool EffectAnimation : : alignToBottom ( ) const
2022-12-01 22:06:42 +02:00
{
return effectFlags & ALIGN_TO_BOTTOM ;
}
2022-12-25 21:39:55 +02:00
bool EffectAnimation : : forceOnTop ( ) const
2022-12-02 01:55:09 +02:00
{
return effectFlags & FORCE_ON_TOP ;
}
2022-12-25 21:39:55 +02:00
bool EffectAnimation : : screenFill ( ) const
2022-12-02 01:55:09 +02:00
{
return effectFlags & SCREEN_FILL ;
}
2022-12-25 21:39:55 +02:00
void EffectAnimation : : onEffectFinished ( )
2022-12-01 22:06:42 +02:00
{
effectFinished = true ;
}
2022-12-25 21:39:55 +02:00
void EffectAnimation : : playEffect ( )
2011-12-22 16:05:19 +03:00
{
2022-12-02 01:55:09 +02:00
if ( effectFinished )
return ;
2022-12-13 13:58:16 +02:00
for ( auto & elem : owner . effectsController - > battleEffects )
2011-12-22 16:05:19 +03:00
{
2013-06-29 16:05:48 +03:00
if ( elem . effectID = = ID )
2011-12-22 16:05:19 +03:00
{
2013-07-16 21:12:47 +03:00
elem . currentFrame + = AnimationControls : : getSpellEffectSpeed ( ) * GH . mainFPSmng - > getElapsedMilliseconds ( ) / 1000 ;
2011-12-22 16:05:19 +03:00
2017-09-05 16:21:44 +02:00
if ( elem . currentFrame > = elem . animation - > size ( ) )
2011-12-22 16:05:19 +03:00
{
2022-12-02 01:55:09 +02:00
elem . currentFrame = elem . animation - > size ( ) - 1 ;
2022-12-01 22:06:42 +02:00
onEffectFinished ( ) ;
break ;
2011-12-22 16:05:19 +03:00
}
}
}
}
2022-12-25 21:39:55 +02:00
void EffectAnimation : : clearEffect ( )
2011-12-22 16:05:19 +03:00
{
2022-12-13 13:58:16 +02:00
auto & effects = owner . effectsController - > battleEffects ;
2022-11-27 20:01:52 +02:00
2022-12-13 15:10:31 +02:00
vstd : : erase_if ( effects , [ & ] ( const BattleEffect & effect ) {
return effect . effectID = = ID ;
} ) ;
2013-04-09 17:31:36 +03:00
}
2022-12-01 22:06:42 +02:00
2022-12-25 21:39:55 +02:00
EffectAnimation : : ~ EffectAnimation ( )
2022-12-01 22:06:42 +02:00
{
assert ( effectFinished ) ;
}
2022-12-13 18:49:35 +02:00
HeroCastAnimation : : HeroCastAnimation ( BattleInterface & owner , std : : shared_ptr < BattleHero > hero , BattleHex dest , const CStack * defender , const CSpell * spell ) :
BattleAnimation ( owner ) ,
projectileEmitted ( false ) ,
hero ( hero ) ,
target ( defender ) ,
tile ( dest ) ,
spell ( spell )
2022-12-01 22:06:42 +02:00
{
2022-12-13 18:49:35 +02:00
}
bool HeroCastAnimation : : init ( )
{
hero - > setPhase ( EHeroAnimType : : CAST_SPELL ) ;
2022-12-11 12:29:11 +02:00
2022-12-13 18:49:35 +02:00
hero - > onPhaseFinished ( [ & ] ( ) {
delete this ;
} ) ;
initializeProjectile ( ) ;
return true ;
2022-12-01 22:06:42 +02:00
}
2022-12-13 18:49:35 +02:00
void HeroCastAnimation : : initializeProjectile ( )
{
2022-12-14 14:48:02 +02:00
// spell has no projectile to play, ignore this step
2022-12-13 18:49:35 +02:00
if ( spell - > animationInfo . projectile . empty ( ) )
return ;
2022-12-14 14:48:02 +02:00
// targeted spells should have well, target
assert ( tile . isValid ( ) ) ;
2023-01-05 14:16:01 +02:00
Point srccoord = hero - > pos . center ( ) - hero - > parent - > pos . topLeft ( ) ;
2022-12-13 18:49:35 +02:00
Point destcoord = owner . stacksController - > getStackPositionAtHex ( tile , target ) ; //position attacked by projectile
2022-12-01 22:06:42 +02:00
2022-12-13 18:49:35 +02:00
destcoord + = Point ( 222 , 265 ) ; // FIXME: what are these constants?
owner . projectilesController - > createSpellProjectile ( nullptr , srccoord , destcoord , spell ) ;
}
void HeroCastAnimation : : emitProjectile ( )
2022-12-01 22:06:42 +02:00
{
2022-12-13 18:49:35 +02:00
if ( projectileEmitted )
return ;
2022-12-01 22:06:42 +02:00
2022-12-13 18:49:35 +02:00
//spell has no projectile to play, skip this step and immediately play hit animations
if ( spell - > animationInfo . projectile . empty ( ) )
emitAnimationEvent ( ) ;
else
owner . projectilesController - > emitStackProjectile ( nullptr ) ;
2022-12-01 22:06:42 +02:00
2022-12-13 18:49:35 +02:00
projectileEmitted = true ;
}
2022-12-01 22:06:42 +02:00
2022-12-13 18:49:35 +02:00
void HeroCastAnimation : : emitAnimationEvent ( )
{
2023-03-19 01:40:31 +02:00
owner . executeAnimationStage ( EAnimationEvents : : HIT ) ;
2022-12-13 18:49:35 +02:00
}
void HeroCastAnimation : : nextFrame ( )
{
float frame = hero - > getFrame ( ) ;
2022-12-14 12:04:37 +02:00
if ( frame < 4.0f ) // middle point of animation //TODO: un-hardcode
2022-12-13 18:49:35 +02:00
return ;
if ( ! projectileEmitted )
{
emitProjectile ( ) ;
hero - > pause ( ) ;
return ;
}
2022-12-15 23:24:03 +02:00
if ( ! owner . projectilesController - > hasActiveProjectile ( nullptr , false ) )
2022-12-13 18:49:35 +02:00
{
emitAnimationEvent ( ) ;
2022-12-14 12:04:37 +02:00
//TODO: check H3 - it is possible that hero animation should be paused until hit effect is over, not just projectile
2022-12-13 18:49:35 +02:00
hero - > play ( ) ;
}
2022-12-01 22:06:42 +02:00
}