2011-12-22 16:05:19 +03:00
# include "StdInc.h"
# include "CBattleAnimations.h"
# include <boost/math/constants/constants.hpp>
2013-07-06 19:10:20 +03:00
2011-12-22 16:05:19 +03:00
# include "CBattleInterfaceClasses.h"
2013-07-06 19:10:20 +03:00
# include "CBattleInterface.h"
2011-12-22 16:05:19 +03:00
# include "CCreatureAnimation.h"
2013-07-06 19:10:20 +03:00
# include "../CDefHandler.h"
# include "../CGameInfo.h"
# include "../CMusicHandler.h"
2011-12-22 16:05:19 +03:00
# include "../CPlayerInterface.h"
# include "../Graphics.h"
2013-04-07 14:52:07 +03:00
# include "../gui/CCursorHandler.h"
2013-07-06 19:10:20 +03:00
# include "../gui/CGuiHandler.h"
# include "../gui/SDL_Extensions.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"
2013-07-06 19:10:20 +03:00
# include "../../lib/CTownHandler.h"
2014-07-15 10:14:49 +03:00
# include "../../lib/mapObjects/CGTownInstance.h"
2015-02-02 10:25:26 +02:00
# include "../../lib/spells/CSpellHandler.h"
2011-12-22 16:05:19 +03:00
2013-07-07 22:44:08 +03:00
/*
* CBattleAnimations . cpp , part of VCMI engine
*
* 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
CBattleAnimation : : CBattleAnimation ( CBattleInterface * _owner )
2013-07-06 19:10:20 +03:00
: owner ( _owner ) , ID ( _owner - > animIDhelper + + )
2013-07-16 21:12:47 +03:00
{
logAnim - > traceStream ( ) < < " Animation # " < < ID < < " created " ;
}
CBattleAnimation : : ~ CBattleAnimation ( )
{
logAnim - > traceStream ( ) < < " Animation # " < < ID < < " deleted " ;
}
2011-12-22 16:05:19 +03:00
void CBattleAnimation : : endAnim ( )
{
2013-07-16 21:12:47 +03:00
logAnim - > traceStream ( ) < < " Animation # " < < ID < < " ended, type is " < < typeid ( this ) . name ( ) ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : owner - > pendingAnims )
2011-12-22 16:05:19 +03:00
{
2013-06-29 16:05:48 +03:00
if ( elem . first = = this )
2011-12-22 16:05:19 +03:00
{
2013-06-29 16:05:48 +03:00
elem . first = nullptr ;
2011-12-22 16:05:19 +03:00
}
}
}
bool CBattleAnimation : : isEarliest ( bool perStackConcurrency )
{
int lowestMoveID = owner - > animIDhelper + 5 ;
CBattleStackAnimation * thAnim = dynamic_cast < CBattleStackAnimation * > ( this ) ;
CSpellEffectAnimation * thSen = dynamic_cast < CSpellEffectAnimation * > ( this ) ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : owner - > pendingAnims )
2011-12-22 16:05:19 +03:00
{
2013-08-06 18:25:51 +03:00
2013-06-29 16:05:48 +03:00
CBattleStackAnimation * stAnim = dynamic_cast < CBattleStackAnimation * > ( elem . first ) ;
CSpellEffectAnimation * sen = dynamic_cast < CSpellEffectAnimation * > ( elem . first ) ;
2011-12-22 16:05:19 +03:00
if ( perStackConcurrency & & stAnim & & thAnim & & stAnim - > stack - > ID ! = thAnim - > stack - > ID )
continue ;
2013-07-16 21:12:47 +03:00
if ( perStackConcurrency & & sen & & thSen & & sen ! = thSen )
2011-12-22 16:05:19 +03:00
continue ;
CReverseAnimation * revAnim = dynamic_cast < CReverseAnimation * > ( stAnim ) ;
if ( revAnim & & thAnim & & stAnim & & stAnim - > stack - > ID = = thAnim - > stack - > ID & & revAnim - > priority )
return false ;
2013-06-29 16:05:48 +03:00
if ( elem . first )
vstd : : amin ( lowestMoveID , elem . first - > ID ) ;
2011-12-22 16:05:19 +03:00
}
return ( ID = = lowestMoveID ) | | ( lowestMoveID = = ( owner - > animIDhelper + 5 ) ) ;
}
2013-07-06 19:10:20 +03:00
CBattleStackAnimation : : CBattleStackAnimation ( CBattleInterface * owner , const CStack * stack )
: CBattleAnimation ( owner ) ,
myAnim ( owner - > creAnims [ stack - > ID ] ) ,
stack ( stack )
2013-09-27 22:42:17 +03:00
{
assert ( myAnim ) ;
}
2011-12-22 16:05:19 +03:00
void CAttackAnimation : : nextFrame ( )
{
2013-07-06 19:10:20 +03:00
if ( myAnim - > getType ( ) ! = group )
{
myAnim - > setType ( group ) ;
myAnim - > onAnimationReset + = std : : bind ( & CAttackAnimation : : endAnim , this ) ;
}
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
if ( ! soundPlayed )
2011-12-22 16:05:19 +03:00
{
if ( shooting )
CCS - > soundh - > playSound ( battle_sound ( attackingStack - > getCreature ( ) , shoot ) ) ;
else
CCS - > soundh - > playSound ( battle_sound ( attackingStack - > getCreature ( ) , attack ) ) ;
2013-07-06 19:10:20 +03:00
soundPlayed = true ;
2011-12-22 16:05:19 +03:00
}
2013-07-06 19:10:20 +03:00
CBattleAnimation : : nextFrame ( ) ;
}
void CAttackAnimation : : endAnim ( )
{
myAnim - > setType ( CCreatureAnim : : HOLDING ) ;
CBattleStackAnimation : : endAnim ( ) ;
2011-12-22 16:05:19 +03:00
}
bool CAttackAnimation : : checkInitialConditions ( )
{
2013-07-16 21:12:47 +03:00
for ( auto & elem : owner - > pendingAnims )
{
CBattleStackAnimation * stAnim = dynamic_cast < CBattleStackAnimation * > ( elem . first ) ;
CReverseAnimation * revAnim = dynamic_cast < CReverseAnimation * > ( stAnim ) ;
2017-05-28 13:39:36 +02:00
if ( revAnim & & attackedStack ) // enemy must be fully reversed
2013-07-16 21:12:47 +03:00
{
if ( revAnim - > stack - > ID = = attackedStack - > ID )
return false ;
}
}
2011-12-22 16:05:19 +03:00
return isEarliest ( false ) ;
}
CAttackAnimation : : CAttackAnimation ( CBattleInterface * _owner , const CStack * attacker , BattleHex _dest , const CStack * defender )
2016-11-27 16:48:18 +02:00
: CBattleStackAnimation ( _owner , attacker ) ,
shooting ( false ) , group ( CCreatureAnim : : SHOOT_FRONT ) ,
soundPlayed ( false ) ,
dest ( _dest ) , attackedStack ( defender ) , 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 " ) ;
2016-11-27 16:48:18 +02:00
bool isCatapultAttack = attackingStack - > hasBonusOfType ( Bonus : : CATAPULT )
2013-11-03 19:44:47 +03:00
& & owner - > getCurrentPlayerInterface ( ) - > cb - > battleHexToWallPart ( _dest ) > = 0 ;
2012-04-02 14:38:59 +03:00
assert ( attackedStack | | isCatapultAttack ) ;
2013-11-09 16:49:36 +03:00
UNUSED ( isCatapultAttack ) ;
2011-12-22 16:05:19 +03:00
attackingStackPosBeforeReturn = attackingStack - > position ;
}
CDefenceAnimation : : CDefenceAnimation ( StackAttackedInfo _attackedInfo , CBattleInterface * _owner )
2013-01-21 01:49:34 +03:00
: CBattleStackAnimation ( _owner , _attackedInfo . defender ) ,
2013-08-09 20:37:41 +03:00
attacker ( _attackedInfo . attacker ) , rangedAttack ( _attackedInfo . indirectAttack ) ,
2016-11-27 16:48:18 +02:00
killed ( _attackedInfo . killed ) , timeToWait ( 0 )
2014-09-23 16:02:30 +03:00
{
logAnim - > debugStream ( ) < < " Created defence anim for " < < _attackedInfo . defender - > getName ( ) ;
}
2011-12-22 16:05:19 +03:00
bool CDefenceAnimation : : init ( )
{
2013-06-26 14:18:27 +03:00
if ( attacker = = nullptr & & owner - > battleEffects . size ( ) > 0 )
2011-12-22 16:05:19 +03:00
return false ;
ui32 lowestMoveID = owner - > animIDhelper + 5 ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : owner - > pendingAnims )
2011-12-22 16:05:19 +03:00
{
2013-08-06 18:25:51 +03:00
2013-06-29 16:05:48 +03:00
CDefenceAnimation * defAnim = dynamic_cast < CDefenceAnimation * > ( elem . first ) ;
2011-12-22 16:05:19 +03:00
if ( defAnim & & defAnim - > stack - > ID ! = stack - > ID )
continue ;
2013-06-29 16:05:48 +03:00
CAttackAnimation * attAnim = dynamic_cast < CAttackAnimation * > ( elem . first ) ;
2011-12-22 16:05:19 +03:00
if ( attAnim & & attAnim - > stack - > ID ! = stack - > ID )
continue ;
2013-08-09 20:37:41 +03:00
CSpellEffectAnimation * sen = dynamic_cast < CSpellEffectAnimation * > ( elem . first ) ;
if ( sen )
continue ;
2013-06-29 16:05:48 +03:00
CReverseAnimation * animAsRev = dynamic_cast < CReverseAnimation * > ( elem . first ) ;
2011-12-22 16:05:19 +03:00
2013-08-06 18:25:51 +03:00
if ( animAsRev )
2011-12-22 16:05:19 +03:00
return false ;
2013-06-29 16:05:48 +03:00
if ( elem . first )
vstd : : amin ( lowestMoveID , elem . first - > ID ) ;
2011-12-22 16:05:19 +03:00
}
2013-07-16 21:12:47 +03:00
2011-12-22 16:05:19 +03:00
if ( ID > lowestMoveID )
return false ;
2013-08-06 18:25:51 +03:00
2011-12-22 16:05:19 +03:00
//reverse unit if necessary
2013-11-03 19:44:47 +03:00
if ( attacker & & owner - > getCurrentPlayerInterface ( ) - > cb - > isToReverse ( stack - > position , attacker - > position , owner - > creDir [ stack - > ID ] , attacker - > doubleWide ( ) , owner - > creDir [ attacker - > ID ] ) )
2011-12-22 16:05:19 +03:00
{
owner - > addNewAnim ( new CReverseAnimation ( owner , stack , stack - > position , true ) ) ;
return false ;
}
//unit reversed
2013-07-16 21:12:47 +03:00
if ( rangedAttack ) //delay hit animation
2016-11-27 16:48:18 +02:00
{
2011-12-22 16:05:19 +03:00
for ( std : : list < ProjectileInfo > : : const_iterator it = owner - > projectiles . begin ( ) ; it ! = owner - > projectiles . end ( ) ; + + it )
{
if ( it - > creID = = attacker - > getCreature ( ) - > idNumber )
{
return false ;
}
}
}
2013-07-16 21:12:47 +03:00
// synchronize animation with attacker, unless defending or attacked by shooter:
// wait for 1/2 of attack animation
if ( ! rangedAttack & & getMyAnimType ( ) ! = CCreatureAnim : : DEFENCE )
2011-12-22 16:05:19 +03:00
{
2013-07-17 01:59:39 +03:00
float frameLength = AnimationControls : : getCreatureAnimationSpeed (
2013-07-16 21:12:47 +03:00
stack - > getCreature ( ) , owner - > creAnims [ stack - > ID ] , getMyAnimType ( ) ) ;
2013-07-17 01:59:39 +03:00
timeToWait = myAnim - > framesInGroup ( getMyAnimType ( ) ) * frameLength / 2 ;
2013-07-16 21:12:47 +03:00
myAnim - > setType ( CCreatureAnim : : HOLDING ) ;
2011-12-22 16:05:19 +03:00
}
else
{
2013-07-16 21:12:47 +03:00
timeToWait = 0 ;
startAnimation ( ) ;
2011-12-22 16:05:19 +03:00
}
return true ; //initialized successfuly
}
2013-07-16 21:12:47 +03:00
std : : string CDefenceAnimation : : getMySound ( )
{
if ( killed )
return battle_sound ( stack - > getCreature ( ) , killed ) ;
2015-11-08 00:30:01 +02:00
if ( vstd : : contains ( stack - > state , EBattleStackState : : DEFENDING_ANIM ) )
2013-07-16 21:12:47 +03:00
return battle_sound ( stack - > getCreature ( ) , defend ) ;
2015-11-05 00:37:53 +02:00
2013-07-16 21:12:47 +03:00
return battle_sound ( stack - > getCreature ( ) , wince ) ;
}
CCreatureAnim : : EAnimType CDefenceAnimation : : getMyAnimType ( )
{
if ( killed )
return CCreatureAnim : : DEATH ;
2016-11-27 16:48:18 +02:00
2015-11-08 00:30:01 +02:00
if ( vstd : : contains ( stack - > state , EBattleStackState : : DEFENDING_ANIM ) )
2013-07-16 21:12:47 +03:00
return CCreatureAnim : : DEFENCE ;
2015-11-05 00:37:53 +02:00
2013-07-16 21:12:47 +03:00
return CCreatureAnim : : HITTED ;
}
void CDefenceAnimation : : startAnimation ( )
{
CCS - > soundh - > playSound ( getMySound ( ) ) ;
myAnim - > setType ( getMyAnimType ( ) ) ;
myAnim - > onAnimationReset + = std : : bind ( & CDefenceAnimation : : endAnim , this ) ;
}
2011-12-22 16:05:19 +03:00
void CDefenceAnimation : : nextFrame ( )
{
2013-07-16 21:12:47 +03:00
if ( timeToWait > 0 )
{
timeToWait - = float ( GH . mainFPSmng - > getElapsedMilliseconds ( ) ) / 1000 ;
if ( timeToWait < = 0 )
startAnimation ( ) ;
}
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
CBattleAnimation : : nextFrame ( ) ;
2011-12-22 16:05:19 +03:00
}
void CDefenceAnimation : : endAnim ( )
{
2013-07-06 19:10:20 +03:00
if ( killed )
myAnim - > setType ( CCreatureAnim : : DEAD ) ;
else
myAnim - > setType ( CCreatureAnim : : HOLDING ) ;
2011-12-22 16:05:19 +03:00
CBattleAnimation : : endAnim ( ) ;
delete this ;
}
2016-11-27 16:48:18 +02:00
CDummyAnimation : : CDummyAnimation ( CBattleInterface * _owner , int howManyFrames )
2013-07-06 19:10:20 +03:00
: CBattleAnimation ( _owner ) , counter ( 0 ) , howMany ( howManyFrames )
2015-09-12 23:01:36 +02:00
{
logAnim - > debugStream ( ) < < " Created dummy animation for " < < howManyFrames < < " frames " ;
}
2011-12-22 16:05:19 +03:00
bool CDummyAnimation : : init ( )
{
return true ;
}
void CDummyAnimation : : nextFrame ( )
{
counter + + ;
if ( counter > howMany )
endAnim ( ) ;
}
void CDummyAnimation : : endAnim ( )
{
CBattleAnimation : : endAnim ( ) ;
delete this ;
}
bool CMeleeAttackAnimation : : init ( )
{
if ( ! CAttackAnimation : : checkInitialConditions ( ) )
return false ;
2013-07-06 19:10:20 +03:00
if ( ! attackingStack | | myAnim - > isDead ( ) )
2011-12-22 16:05:19 +03:00
{
endAnim ( ) ;
2016-11-27 16:48:18 +02:00
2011-12-22 16:05:19 +03:00
return false ;
}
2014-03-23 19:36:16 +03:00
bool toReverse = owner - > getCurrentPlayerInterface ( ) - > cb - > isToReverse ( attackingStackPosBeforeReturn , attackedStack - > position , owner - > creDir [ stack - > ID ] , attackedStack - > doubleWide ( ) , owner - > creDir [ attackedStack - > ID ] ) ;
2011-12-22 16:05:19 +03:00
2012-11-29 18:02:55 +03:00
if ( toReverse )
2011-12-22 16:05:19 +03:00
{
owner - > addNewAnim ( new CReverseAnimation ( owner , stack , attackingStackPosBeforeReturn , true ) ) ;
return false ;
}
2013-07-16 21:12:47 +03:00
// opponent must face attacker ( = different directions) before he can be attacked
if ( attackingStack & & attackedStack & &
owner - > creDir [ attackingStack - > ID ] = = owner - > creDir [ attackedStack - > ID ] )
return false ;
2011-12-22 16:05:19 +03:00
//reversed
shooting = false ;
static const CCreatureAnim : : EAnimType mutPosToGroup [ ] = { CCreatureAnim : : ATTACK_UP , CCreatureAnim : : ATTACK_UP ,
CCreatureAnim : : ATTACK_FRONT , CCreatureAnim : : ATTACK_DOWN , CCreatureAnim : : ATTACK_DOWN , CCreatureAnim : : ATTACK_FRONT } ;
int revShiftattacker = ( attackingStack - > attackerOwned ? - 1 : 1 ) ;
int mutPos = BattleHex : : mutualPosition ( attackingStackPosBeforeReturn , dest ) ;
if ( mutPos = = - 1 & & attackingStack - > doubleWide ( ) )
{
mutPos = BattleHex : : mutualPosition ( attackingStackPosBeforeReturn + revShiftattacker , attackedStack - > position ) ;
}
if ( mutPos = = - 1 & & attackedStack - > doubleWide ( ) )
{
mutPos = BattleHex : : mutualPosition ( attackingStackPosBeforeReturn , attackedStack - > occupiedHex ( ) ) ;
}
if ( mutPos = = - 1 & & attackedStack - > doubleWide ( ) & & attackingStack - > doubleWide ( ) )
{
mutPos = BattleHex : : mutualPosition ( attackingStackPosBeforeReturn + revShiftattacker , attackedStack - > occupiedHex ( ) ) ;
}
switch ( mutPos ) //attack direction
{
case 0 : case 1 : case 2 : case 3 : case 4 : case 5 :
group = mutPosToGroup [ mutPos ] ;
break ;
default :
2016-03-12 03:41:27 +02:00
logGlobal - > errorStream ( ) < < " Critical Error! Wrong dest in stackAttacking! dest: " < < dest < < " attacking stack pos: " < < attackingStackPosBeforeReturn < < " mutual pos: " < < mutPos ;
2011-12-22 16:05:19 +03:00
group = CCreatureAnim : : ATTACK_FRONT ;
break ;
}
return true ;
}
CMeleeAttackAnimation : : CMeleeAttackAnimation ( CBattleInterface * _owner , const CStack * attacker , BattleHex _dest , const CStack * _attacked )
2016-11-27 16:48:18 +02:00
: CAttackAnimation ( _owner , attacker , _dest , _attacked )
2014-09-23 16:02:30 +03:00
{
logAnim - > debugStream ( ) < < " Created melee attack anim for " < < attacker - > getName ( ) ;
}
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
void CMeleeAttackAnimation : : endAnim ( )
2011-12-22 16:05:19 +03:00
{
2013-07-06 19:10:20 +03:00
CAttackAnimation : : endAnim ( ) ;
delete this ;
2011-12-22 16:05:19 +03:00
}
2013-07-06 19:10:20 +03:00
bool CMovementAnimation : : shouldRotate ( )
2011-12-22 16:05:19 +03:00
{
2013-07-07 22:44:08 +03:00
Point begPosition = CClickableHex : : getXYUnitAnim ( oldPos , stack , owner ) ;
Point endPosition = CClickableHex : : getXYUnitAnim ( nextHex , stack , owner ) ;
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
if ( ( begPosition . x > endPosition . x ) & & owner - > creDir [ stack - > ID ] = = true )
{
return true ;
}
else if ( ( begPosition . x < endPosition . x ) & & owner - > creDir [ stack - > ID ] = = false )
{
return true ;
}
return false ;
2011-12-22 16:05:19 +03:00
}
bool CMovementAnimation : : init ( )
{
2013-07-06 19:10:20 +03:00
if ( ! isEarliest ( false ) )
2011-12-22 16:05:19 +03:00
return false ;
2013-07-06 19:10:20 +03:00
if ( ! stack | | myAnim - > isDead ( ) )
2011-12-22 16:05:19 +03:00
{
endAnim ( ) ;
return false ;
}
2013-07-06 19:10:20 +03:00
if ( owner - > creAnims [ stack - > ID ] - > framesInGroup ( CCreatureAnim : : MOVING ) = = 0 | |
stack - > hasBonus ( Selector : : typeSubtype ( Bonus : : FLYING , 1 ) ) )
2012-09-29 11:35:31 +03:00
{
2013-07-06 19:10:20 +03:00
//no movement or teleport, end immediately
2012-09-29 11:35:31 +03:00
endAnim ( ) ;
return false ;
}
2011-12-22 16:05:19 +03:00
//reverse unit if necessary
2013-07-06 19:10:20 +03:00
if ( shouldRotate ( ) )
2011-12-22 16:05:19 +03:00
{
2013-07-06 19:10:20 +03:00
// it seems that H3 does NOT plays full rotation animation here in most situations
// Logical since it takes quite a lot of time
if ( curentMoveIndex = = 0 ) // full rotation only for moving towards first tile.
{
owner - > addNewAnim ( new CReverseAnimation ( owner , stack , oldPos , true ) ) ;
return false ;
}
else
{
CReverseAnimation : : rotateStack ( owner , stack , oldPos ) ;
}
2011-12-22 16:05:19 +03:00
}
2013-07-06 19:10:20 +03:00
if ( myAnim - > getType ( ) ! = CCreatureAnim : : MOVING )
2011-12-22 16:05:19 +03:00
{
2013-07-06 19:10:20 +03:00
myAnim - > setType ( CCreatureAnim : : MOVING ) ;
2011-12-22 16:05:19 +03:00
}
2013-07-06 19:10:20 +03:00
if ( owner - > moveSoundHander = = - 1 )
2012-05-15 19:29:40 +03:00
{
2013-07-06 19:10:20 +03:00
owner - > moveSoundHander = CCS - > soundh - > playSound ( battle_sound ( stack - > getCreature ( ) , move ) , - 1 ) ;
2012-05-15 19:29:40 +03:00
}
2011-12-22 16:05:19 +03:00
2013-07-07 22:44:08 +03:00
Point begPosition = CClickableHex : : getXYUnitAnim ( oldPos , stack , owner ) ;
Point endPosition = CClickableHex : : getXYUnitAnim ( nextHex , stack , owner ) ;
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
timeToMove = AnimationControls : : getMovementDuration ( stack - > getCreature ( ) ) ;
begX = begPosition . x ;
begY = begPosition . y ;
progress = 0 ;
distanceX = endPosition . x - begPosition . x ;
distanceY = endPosition . y - begPosition . y ;
if ( stack - > hasBonus ( Selector : : type ( Bonus : : FLYING ) ) )
2011-12-22 16:05:19 +03:00
{
2013-07-06 19:10:20 +03:00
float distance = sqrt ( distanceX * distanceX + distanceY * distanceY ) ;
2013-07-16 21:12:47 +03:00
timeToMove * = AnimationControls : : getFlightDistance ( stack - > getCreature ( ) ) / distance ;
2011-12-22 16:05:19 +03:00
}
return true ;
}
void CMovementAnimation : : nextFrame ( )
{
2013-07-06 19:10:20 +03:00
progress + = float ( GH . mainFPSmng - > getElapsedMilliseconds ( ) ) / 1000 * timeToMove ;
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
2013-07-06 19:10:20 +03:00
CBattleAnimation : : nextFrame ( ) ;
if ( progress > = 1.0 )
2011-12-22 16:05:19 +03:00
{
// Sets the position of the creature animation sprites
2013-07-07 22:44:08 +03:00
Point coords = CClickableHex : : getXYUnitAnim ( nextHex , stack , owner ) ;
2013-07-06 19:10:20 +03:00
myAnim - > pos = 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 + + ;
oldPos = nextHex ;
nextHex = destTiles [ curentMoveIndex ] ;
2011-12-22 16:05:19 +03:00
// re-init animation
2013-06-29 16:05:48 +03:00
for ( auto & elem : owner - > pendingAnims )
2011-12-22 16:05:19 +03:00
{
2013-06-29 16:05:48 +03:00
if ( elem . first = = this )
2011-12-22 16:05:19 +03:00
{
2013-06-29 16:05:48 +03:00
elem . second = false ;
2011-12-22 16:05:19 +03:00
break ;
}
}
}
else
endAnim ( ) ;
}
}
void CMovementAnimation : : endAnim ( )
{
2013-07-06 19:10:20 +03:00
assert ( stack ) ;
2011-12-22 16:05:19 +03:00
2013-07-07 22:44:08 +03:00
myAnim - > pos = CClickableHex : : getXYUnitAnim ( nextHex , stack , owner ) ;
2011-12-22 16:05:19 +03:00
CBattleAnimation : : endAnim ( ) ;
2013-07-06 19:10:20 +03:00
owner - > addNewAnim ( new CMovementEndAnimation ( owner , stack , nextHex ) ) ;
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
if ( owner - > moveSoundHander ! = - 1 )
2011-12-22 16:05:19 +03:00
{
2013-07-06 19:10:20 +03:00
CCS - > soundh - > stopSound ( owner - > moveSoundHander ) ;
owner - > moveSoundHander = - 1 ;
2011-12-22 16:05:19 +03:00
}
delete this ;
}
CMovementAnimation : : CMovementAnimation ( CBattleInterface * _owner , const CStack * _stack , std : : vector < BattleHex > _destTiles , int _distance )
2013-07-06 19:10:20 +03:00
: CBattleStackAnimation ( _owner , _stack ) ,
destTiles ( _destTiles ) ,
curentMoveIndex ( 0 ) ,
oldPos ( stack - > position ) ,
begX ( 0 ) , begY ( 0 ) ,
distanceX ( 0 ) , distanceY ( 0 ) ,
timeToMove ( 0.0 ) ,
2013-07-19 19:35:16 +03:00
progress ( 0.0 ) ,
nextHex ( destTiles . front ( ) )
2011-12-22 16:05:19 +03:00
{
2014-09-23 16:02:30 +03:00
logAnim - > debugStream ( ) < < " Created movement anim for " < < stack - > getName ( ) ;
2011-12-22 16:05:19 +03:00
}
CMovementEndAnimation : : CMovementEndAnimation ( CBattleInterface * _owner , const CStack * _stack , BattleHex destTile )
2016-11-27 16:48:18 +02:00
: CBattleStackAnimation ( _owner , _stack ) , destinationTile ( destTile )
2014-09-23 16:02:30 +03:00
{
logAnim - > debugStream ( ) < < " Created movement end anim for " < < stack - > getName ( ) ;
}
2011-12-22 16:05:19 +03:00
bool CMovementEndAnimation : : init ( )
{
if ( ! isEarliest ( true ) )
return false ;
2013-07-06 19:10:20 +03:00
if ( ! stack | | myAnim - > framesInGroup ( CCreatureAnim : : MOVE_END ) = = 0 | |
myAnim - > isDead ( ) )
2011-12-22 16:05:19 +03:00
{
endAnim ( ) ;
return false ;
}
CCS - > soundh - > playSound ( battle_sound ( stack - > getCreature ( ) , endMoving ) ) ;
2013-07-06 19:10:20 +03:00
myAnim - > setType ( CCreatureAnim : : MOVE_END ) ;
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
myAnim - > onAnimationReset + = std : : bind ( & CMovementEndAnimation : : endAnim , 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
}
void CMovementEndAnimation : : endAnim ( )
{
CBattleAnimation : : endAnim ( ) ;
2013-07-06 19:10:20 +03:00
if ( myAnim - > getType ( ) ! = CCreatureAnim : : DEAD )
myAnim - > setType ( CCreatureAnim : : HOLDING ) ; //resetting to default
2011-12-22 16:05:19 +03:00
CCS - > curh - > show ( ) ;
delete this ;
}
CMovementStartAnimation : : CMovementStartAnimation ( CBattleInterface * _owner , const CStack * _stack )
2016-11-27 16:48:18 +02:00
: CBattleStackAnimation ( _owner , _stack )
2014-09-23 16:02:30 +03:00
{
logAnim - > debugStream ( ) < < " Created movement start anim for " < < stack - > getName ( ) ;
}
2011-12-22 16:05:19 +03:00
bool CMovementStartAnimation : : init ( )
{
if ( ! isEarliest ( false ) )
return false ;
2013-07-06 19:10:20 +03:00
if ( ! stack | | myAnim - > isDead ( ) )
2011-12-22 16:05:19 +03:00
{
CMovementStartAnimation : : endAnim ( ) ;
return false ;
}
CCS - > soundh - > playSound ( battle_sound ( stack - > getCreature ( ) , startMoving ) ) ;
2013-07-06 19:10:20 +03:00
myAnim - > setType ( CCreatureAnim : : MOVE_START ) ;
myAnim - > onAnimationReset + = std : : bind ( & CMovementStartAnimation : : endAnim , this ) ;
2011-12-22 16:05:19 +03:00
return true ;
}
void CMovementStartAnimation : : endAnim ( )
{
CBattleAnimation : : endAnim ( ) ;
delete this ;
}
CReverseAnimation : : CReverseAnimation ( CBattleInterface * _owner , const CStack * stack , BattleHex dest , bool _priority )
2013-07-06 19:10:20 +03:00
: CBattleStackAnimation ( _owner , stack ) , hex ( dest ) , priority ( _priority )
2014-09-23 16:02:30 +03:00
{
logAnim - > debugStream ( ) < < " Created reverse anim for " < < stack - > getName ( ) ;
}
2011-12-22 16:05:19 +03:00
bool CReverseAnimation : : init ( )
{
2013-07-06 19:10:20 +03:00
if ( myAnim = = nullptr | | myAnim - > isDead ( ) )
2011-12-22 16:05:19 +03:00
{
endAnim ( ) ;
return false ; //there is no such creature
}
if ( ! priority & & ! isEarliest ( false ) )
return false ;
2013-07-06 19:10:20 +03:00
if ( myAnim - > framesInGroup ( CCreatureAnim : : TURN_L ) )
2011-12-22 16:05:19 +03:00
{
2013-07-06 19:10:20 +03:00
myAnim - > setType ( CCreatureAnim : : TURN_L ) ;
myAnim - > onAnimationReset + = std : : bind ( & CReverseAnimation : : 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
}
void CReverseAnimation : : endAnim ( )
{
CBattleAnimation : : endAnim ( ) ;
if ( stack - > alive ( ) ) //don't do that if stack is dead
2013-07-06 19:10:20 +03:00
myAnim - > setType ( CCreatureAnim : : HOLDING ) ;
2011-12-22 16:05:19 +03:00
delete this ;
}
2013-07-06 19:10:20 +03:00
void CReverseAnimation : : rotateStack ( CBattleInterface * owner , const CStack * stack , BattleHex hex )
2011-12-22 16:05:19 +03:00
{
2012-09-16 17:36:31 +03:00
owner - > creDir [ stack - > ID ] = ! owner - > creDir [ stack - > ID ] ;
2013-07-07 22:44:08 +03:00
owner - > creAnims [ stack - > ID ] - > pos = CClickableHex : : getXYUnitAnim ( hex , stack , owner ) ;
2013-07-06 19:10:20 +03:00
}
void CReverseAnimation : : setupSecondPart ( )
{
if ( ! stack )
{
endAnim ( ) ;
return ;
}
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
rotateStack ( owner , stack , hex ) ;
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
if ( myAnim - > framesInGroup ( CCreatureAnim : : TURN_R ) )
{
myAnim - > setType ( CCreatureAnim : : TURN_R ) ;
myAnim - > onAnimationReset + = std : : bind ( & CReverseAnimation : : endAnim , this ) ;
}
2011-12-22 16:05:19 +03:00
else
endAnim ( ) ;
}
CShootingAnimation : : CShootingAnimation ( CBattleInterface * _owner , const CStack * attacker , BattleHex _dest , const CStack * _attacked , bool _catapult , int _catapultDmg )
2013-01-21 01:49:34 +03:00
: CAttackAnimation ( _owner , attacker , _dest , _attacked ) , catapultDamage ( _catapultDmg )
2014-09-23 16:02:30 +03:00
{
logAnim - > debugStream ( ) < < " Created shooting anim for " < < stack - > getName ( ) ;
}
2011-12-22 16:05:19 +03:00
bool CShootingAnimation : : init ( )
{
if ( ! CAttackAnimation : : checkInitialConditions ( ) )
return false ;
const CStack * shooter = attackingStack ;
2013-07-06 19:10:20 +03:00
if ( ! shooter | | myAnim - > isDead ( ) )
2011-12-22 16:05:19 +03:00
{
endAnim ( ) ;
return false ;
}
2013-01-31 20:52:10 +03:00
//reverse unit if necessary
2013-11-03 19:44:47 +03:00
if ( attackingStack & & attackedStack & & owner - > getCurrentPlayerInterface ( ) - > cb - > isToReverse ( attackingStack - > position , attackedStack - > position , owner - > creDir [ attackingStack - > ID ] , attackingStack - > doubleWide ( ) , owner - > creDir [ attackedStack - > ID ] ) )
2013-01-31 20:52:10 +03:00
{
owner - > addNewAnim ( new CReverseAnimation ( owner , attackingStack , attackingStack - > position , true ) ) ;
return false ;
}
2013-07-16 21:12:47 +03:00
// opponent must face attacker ( = different directions) before he can be attacked
if ( attackingStack & & attackedStack & &
owner - > creDir [ attackingStack - > ID ] = = owner - > creDir [ attackedStack - > ID ] )
return false ;
2011-12-22 16:05:19 +03:00
// Create the projectile animation
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
// Get further info about the shooter e.g. relative pos of projectile to unit.
// If the creature id is 149 then it's a arrow tower which has no additional info so get the
// actual arrow tower shooter instead.
const CCreature * shooterInfo = shooter - > getCreature ( ) ;
2013-02-09 00:17:39 +03:00
if ( shooterInfo - > idNumber = = CreatureID : : ARROW_TOWERS )
2011-12-22 16:05:19 +03:00
{
2012-10-05 21:03:49 +03:00
int creID = owner - > siegeH - > town - > town - > clientInfo . siegeShooter ;
2011-12-22 16:05:19 +03:00
shooterInfo = CGI - > creh - > creatures [ creID ] ;
}
ProjectileInfo spi ;
2013-07-06 19:10:20 +03:00
spi . shotDone = false ;
2011-12-22 16:05:19 +03:00
spi . creID = shooter - > getCreature ( ) - > idNumber ;
spi . stackID = shooter - > ID ;
2013-04-04 16:18:38 +03:00
// reverse if creature is facing right OR this is non-existing stack that is not tower (war machines)
spi . reverse = attackingStack ? ! owner - > creDir [ attackingStack - > ID ] : shooter - > getCreature ( ) - > idNumber ! = CreatureID : : ARROW_TOWERS ;
2011-12-22 16:05:19 +03:00
spi . step = 0 ;
spi . frameNum = 0 ;
2013-04-04 21:20:25 +03:00
Point fromPos ;
Point destPos ;
2011-12-22 16:05:19 +03:00
2013-04-04 16:18:38 +03:00
// NOTE: two lines below return different positions (very notable with 2-hex creatures). Obtaining via creanims seems to be more precise
2013-04-04 21:20:25 +03:00
fromPos = owner - > creAnims [ spi . stackID ] - > pos . topLeft ( ) ;
2013-04-04 16:18:38 +03:00
//xycoord = CClickableHex::getXYUnitAnim(shooter->position, true, shooter, owner);
2011-12-22 16:05:19 +03:00
2013-07-07 22:44:08 +03:00
destPos = CClickableHex : : getXYUnitAnim ( dest , attackedStack , owner ) ;
2013-04-04 16:18:38 +03:00
2013-04-04 21:20:25 +03:00
// to properly translate coordinates when shooter is rotated
int multiplier = spi . reverse ? - 1 : 1 ;
2013-04-04 16:18:38 +03:00
2013-04-04 22:54:58 +03:00
double projectileAngle = atan2 ( fabs ( ( double ) destPos . y - fromPos . y ) , fabs ( ( double ) destPos . x - fromPos . x ) ) ;
2013-04-04 21:20:25 +03:00
if ( shooter - > position < dest )
projectileAngle = - projectileAngle ;
2011-12-22 16:05:19 +03:00
2013-04-04 21:20:25 +03:00
// Calculate projectile start position. Offsets are read out of the CRANIM.TXT.
if ( projectileAngle > straightAngle )
{
//upper shot
spi . x = fromPos . x + 222 + ( - 25 + shooterInfo - > animation . upperRightMissleOffsetX ) * multiplier ;
spi . y = fromPos . y + 265 + shooterInfo - > animation . upperRightMissleOffsetY ;
}
else if ( projectileAngle < - straightAngle )
{
//lower shot
spi . x = fromPos . x + 222 + ( - 25 + shooterInfo - > animation . lowerRightMissleOffsetX ) * multiplier ;
spi . y = fromPos . y + 265 + shooterInfo - > animation . lowerRightMissleOffsetY ;
}
else
{
//straight shot
spi . x = fromPos . x + 222 + ( - 25 + shooterInfo - > animation . rightMissleOffsetX ) * multiplier ;
spi . y = fromPos . y + 265 + shooterInfo - > animation . rightMissleOffsetY ;
}
destPos + = Point ( 225 , 225 ) ;
2011-12-22 16:05:19 +03:00
2013-04-04 21:20:25 +03:00
// recalculate angle taking in account offsets
//projectileAngle = atan2(fabs(destPos.y - spi.y), fabs(destPos.x - spi.x));
//if(shooter->position < dest)
// projectileAngle = -projectileAngle;
if ( attackedStack )
{
2013-07-06 19:10:20 +03:00
double animSpeed = AnimationControls : : getProjectileSpeed ( ) ; // flight speed of projectile
2013-04-04 21:20:25 +03:00
spi . lastStep = static_cast < int > ( sqrt ( static_cast < double > ( ( destPos . x - spi . x ) * ( destPos . x - spi . x ) + ( destPos . y - spi . y ) * ( destPos . y - spi . y ) ) ) / animSpeed ) ;
2011-12-22 16:05:19 +03:00
if ( spi . lastStep = = 0 )
spi . lastStep = 1 ;
2013-04-04 21:20:25 +03:00
spi . dx = ( destPos . x - spi . x ) / spi . lastStep ;
spi . dy = ( destPos . y - spi . y ) / spi . lastStep ;
2011-12-22 16:05:19 +03:00
}
2016-11-27 16:48:18 +02:00
else
2011-12-22 16:05:19 +03:00
{
// Catapult attack
2013-04-04 21:20:25 +03:00
spi . catapultInfo . reset ( new CatapultProjectileInfo ( Point ( spi . x , spi . y ) , destPos ) ) ;
2011-12-22 16:05:19 +03:00
2013-07-06 19:10:20 +03:00
double animSpeed = AnimationControls : : getProjectileSpeed ( ) / 10 ;
2015-10-12 16:08:18 +02:00
spi . lastStep = std : : abs ( ( destPos . x - spi . x ) / animSpeed ) ;
2013-04-04 21:20:25 +03:00
spi . dx = animSpeed ;
spi . dy = 0 ;
2011-12-22 16:05:19 +03:00
2013-04-04 21:20:25 +03:00
SDL_Surface * img = owner - > idToProjectile [ spi . creID ] - > ourImages [ 0 ] . bitmap ;
2011-12-22 16:05:19 +03:00
2013-04-04 21:20:25 +03:00
// Add explosion anim
Point animPos ( destPos . x - 126 + img - > w / 2 ,
destPos . y - 105 + img - > h / 2 ) ;
owner - > addNewAnim ( new CSpellEffectAnimation ( owner , catapultDamage ? " SGEXPL.DEF " : " CSGRCK.DEF " , animPos . x , animPos . y ) ) ;
2011-12-22 16:05:19 +03:00
}
2013-04-04 16:18:38 +03:00
auto & angles = shooterInfo - > animation . missleFrameAngles ;
double pi = boost : : math : : constants : : pi < double > ( ) ;
2017-02-02 21:27:51 +02:00
if ( owner - > idToProjectile . count ( spi . creID ) = = 0 ) //in some cases (known one: hero grants shooter bonus to unit) the shooter stack's projectile may not be properly initialized
owner - > initStackProjectile ( shooter ) ;
2013-04-04 16:18:38 +03:00
// only frames below maxFrame are usable: anything higher is either no present or we don't know when it should be used
2017-01-26 21:53:28 +02:00
size_t maxFrame = std : : min < size_t > ( angles . size ( ) , owner - > idToProjectile . at ( spi . creID ) - > ourImages . size ( ) ) ;
2013-04-04 16:18:38 +03:00
assert ( maxFrame > 0 ) ;
// values in angles array indicate position from which this frame was rendered, in degrees.
// find frame that has closest angle to one that we need for this shot
size_t bestID = 0 ;
double bestDiff = fabs ( angles [ 0 ] / 180 * pi - projectileAngle ) ;
for ( size_t i = 1 ; i < maxFrame ; i + + )
2011-12-22 16:05:19 +03:00
{
2013-04-04 16:18:38 +03:00
double currentDiff = fabs ( angles [ i ] / 180 * pi - projectileAngle ) ;
if ( currentDiff < bestDiff )
{
bestID = i ;
bestDiff = currentDiff ;
}
2011-12-22 16:05:19 +03:00
}
2013-04-04 16:18:38 +03:00
spi . frameNum = bestID ;
2011-12-22 16:05:19 +03:00
// Set projectile animation start delay which is specified in frames
2013-03-02 19:55:51 +03:00
spi . animStartDelay = shooterInfo - > animation . attackClimaxFrame ;
2011-12-22 16:05:19 +03:00
owner - > projectiles . push_back ( spi ) ;
//attack animation
shooting = true ;
if ( projectileAngle > straightAngle ) //upper shot
group = CCreatureAnim : : SHOOT_UP ;
else if ( projectileAngle < - straightAngle ) //lower shot
group = CCreatureAnim : : SHOOT_DOWN ;
else //straight shot
group = CCreatureAnim : : SHOOT_FRONT ;
return true ;
}
void CShootingAnimation : : nextFrame ( )
{
2013-07-06 19:10:20 +03:00
for ( auto & it : owner - > pendingAnims )
2011-12-22 16:05:19 +03:00
{
2013-07-06 19:10:20 +03:00
CMovementStartAnimation * anim = dynamic_cast < CMovementStartAnimation * > ( it . first ) ;
CReverseAnimation * anim2 = dynamic_cast < CReverseAnimation * > ( it . first ) ;
2011-12-22 16:05:19 +03:00
if ( ( anim & & anim - > stack - > ID = = stack - > ID ) | | ( anim2 & & anim2 - > stack - > ID = = stack - > ID & & anim2 - > priority ) )
return ;
}
CAttackAnimation : : nextFrame ( ) ;
}
void CShootingAnimation : : endAnim ( )
{
2014-06-01 19:48:40 +03:00
// play wall hit/miss sound for catapult attack
if ( ! attackedStack )
{
if ( catapultDamage > 0 )
{
CCS - > soundh - > playSound ( " WALLHIT " ) ;
}
else
{
CCS - > soundh - > playSound ( " WALLMISS " ) ;
}
}
2013-07-06 19:10:20 +03:00
CAttackAnimation : : endAnim ( ) ;
2011-12-22 16:05:19 +03:00
delete this ;
}
2014-11-27 15:51:16 +02:00
CSpellEffectAnimation : : CSpellEffectAnimation ( CBattleInterface * _owner , ui32 _effect , BattleHex _destTile , int _dx , int _dy , bool _Vflip , bool _alignToBottom )
: CBattleAnimation ( _owner ) , effect ( _effect ) , destTile ( _destTile ) , customAnim ( " " ) , x ( - 1 ) , y ( - 1 ) , dx ( _dx ) , dy ( _dy ) , Vflip ( _Vflip ) , alignToBottom ( _alignToBottom )
2014-09-23 17:30:36 +03:00
{
logAnim - > debugStream ( ) < < " Created spell anim for effect # " < < effect ;
}
2011-12-22 16:05:19 +03:00
2014-11-27 15:51:16 +02:00
CSpellEffectAnimation : : CSpellEffectAnimation ( CBattleInterface * _owner , std : : string _customAnim , int _x , int _y , int _dx , int _dy , bool _Vflip , bool _alignToBottom )
: CBattleAnimation ( _owner ) , effect ( - 1 ) , destTile ( BattleHex : : INVALID ) , customAnim ( _customAnim ) , x ( _x ) , y ( _y ) , dx ( _dx ) , dy ( _dy ) , Vflip ( _Vflip ) , alignToBottom ( _alignToBottom )
2014-09-23 17:30:36 +03:00
{
logAnim - > debugStream ( ) < < " Created spell anim for " < < customAnim ;
}
2011-12-22 16:05:19 +03:00
2014-11-27 15:51:16 +02:00
CSpellEffectAnimation : : CSpellEffectAnimation ( CBattleInterface * _owner , std : : string _customAnim , BattleHex _destTile , bool _Vflip , bool _alignToBottom )
: CBattleAnimation ( _owner ) , effect ( - 1 ) , destTile ( _destTile ) , customAnim ( _customAnim ) , x ( - 1 ) , y ( - 1 ) , dx ( 0 ) , dy ( 0 ) , Vflip ( _Vflip ) , alignToBottom ( _alignToBottom )
{
2016-11-27 16:48:18 +02:00
logAnim - > debugStream ( ) < < " Created spell anim for " < < customAnim ;
2014-11-27 15:51:16 +02:00
}
2011-12-22 16:05:19 +03:00
bool CSpellEffectAnimation : : init ( )
{
if ( ! isEarliest ( true ) )
return false ;
2016-11-27 16:48:18 +02:00
2014-11-27 15:51:16 +02:00
if ( customAnim . empty ( ) & & effect ! = ui32 ( - 1 ) & & ! graphics - > battleACToDef [ effect ] . empty ( ) )
2016-11-27 16:48:18 +02:00
{
2014-11-27 15:51:16 +02:00
customAnim = graphics - > battleACToDef [ effect ] [ 0 ] ;
}
2016-11-27 16:48:18 +02:00
2014-11-27 15:51:16 +02:00
if ( customAnim . empty ( ) )
2011-12-22 16:05:19 +03:00
{
2014-11-27 15:51:16 +02:00
endAnim ( ) ;
2016-11-27 16:48:18 +02:00
return false ;
2014-11-27 15:51:16 +02:00
}
2016-11-27 16:48:18 +02:00
2014-11-27 15:51:16 +02:00
const bool areaEffect = ( ! destTile . isValid ( ) & & x = = - 1 & & y = = - 1 ) ;
2011-12-22 16:05:19 +03:00
2016-11-27 16:48:18 +02:00
if ( areaEffect ) //f.e. armageddon
2014-11-27 15:51:16 +02:00
{
CDefHandler * anim = CDefHandler : : giveDef ( customAnim ) ;
2011-12-22 16:05:19 +03:00
2014-11-27 15:51:16 +02:00
for ( int i = 0 ; i * anim - > width < owner - > pos . w ; + + i )
{
for ( int j = 0 ; j * anim - > height < owner - > pos . h ; + + j )
2011-12-22 16:05:19 +03:00
{
2014-11-27 15:51:16 +02:00
BattleEffect be ;
be . effectID = ID ;
be . anim = CDefHandler : : giveDef ( customAnim ) ;
if ( Vflip )
2011-12-22 16:05:19 +03:00
{
2014-11-27 15:51:16 +02:00
for ( auto & elem : be . anim - > ourImages )
2011-12-22 16:05:19 +03:00
{
2014-11-27 15:51:16 +02:00
CSDL_Ext : : VflipSurf ( elem . bitmap ) ;
2011-12-22 16:05:19 +03:00
}
}
2014-11-27 15:51:16 +02:00
be . currentFrame = 0 ;
be . maxFrame = be . anim - > ourImages . size ( ) ;
be . x = i * anim - > width + owner - > pos . x ;
be . y = j * anim - > height + owner - > pos . y ;
be . position = BattleHex : : INVALID ;
owner - > battleEffects . push_back ( be ) ;
2011-12-22 16:05:19 +03:00
}
}
2016-11-27 16:48:18 +02:00
2014-11-27 15:51:16 +02:00
delete anim ;
2011-12-22 16:05:19 +03:00
}
else // Effects targeted at a specific creature/hex.
{
2014-11-27 15:51:16 +02:00
2013-11-03 19:44:47 +03:00
const CStack * destStack = owner - > getCurrentPlayerInterface ( ) - > cb - > battleGetStackByPos ( destTile , false ) ;
2017-06-26 18:50:35 +02:00
Rect & tilePos = owner - > bfield [ destTile ] - > pos ;
2011-12-22 16:05:19 +03:00
BattleEffect be ;
be . effectID = ID ;
2014-11-27 15:51:16 +02:00
be . anim = CDefHandler : : giveDef ( customAnim ) ;
2011-12-22 16:05:19 +03:00
if ( Vflip )
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : be . anim - > ourImages )
2011-12-22 16:05:19 +03:00
{
2013-06-29 16:05:48 +03:00
CSDL_Ext : : VflipSurf ( elem . bitmap ) ;
2011-12-22 16:05:19 +03:00
}
}
2013-07-16 21:12:47 +03:00
be . currentFrame = 0 ;
2011-12-22 16:05:19 +03:00
be . maxFrame = be . anim - > ourImages . size ( ) ;
2016-11-27 16:48:18 +02:00
2014-11-27 15:51:16 +02:00
//todo: lightning anim frame count override
2016-11-27 16:48:18 +02:00
2014-11-27 15:51:16 +02:00
// if(effect == 1)
// be.maxFrame = 3;
2011-12-22 16:05:19 +03:00
2014-11-27 15:51:16 +02:00
if ( x = = - 1 )
{
be . x = tilePos . x + tilePos . w / 2 - be . anim - > width / 2 ;
}
else
2011-12-22 16:05:19 +03:00
{
be . x = x ;
2014-11-27 15:51:16 +02:00
}
2016-11-27 16:48:18 +02:00
2014-11-27 15:51:16 +02:00
if ( y = = - 1 )
{
if ( alignToBottom )
be . y = tilePos . y + tilePos . h - be . anim - > height ;
else
be . y = tilePos . y - be . anim - > height / 2 ;
}
else
{
2011-12-22 16:05:19 +03:00
be . y = y ;
}
// Correction for 2-hex creatures.
2013-06-26 14:18:27 +03:00
if ( destStack ! = nullptr & & destStack - > doubleWide ( ) )
2011-12-22 16:05:19 +03:00
be . x + = ( destStack - > attackerOwned ? - 1 : 1 ) * tilePos . w / 2 ;
2013-07-10 13:45:51 +03:00
//Indicate if effect should be drawn on top of everything or just on top of the hex
2014-11-27 16:39:37 +02:00
be . position = destTile ;
2013-07-10 13:45:51 +03:00
2011-12-22 16:05:19 +03:00
owner - > battleEffects . push_back ( be ) ;
2014-11-27 15:51:16 +02:00
2011-12-22 16:05:19 +03:00
}
2016-11-27 16:48:18 +02:00
//battleEffects
2011-12-22 16:05:19 +03:00
return true ;
}
void CSpellEffectAnimation : : nextFrame ( )
{
//notice: there may be more than one effect in owner->battleEffects correcponding to this animation (ie. armageddon)
2013-06-29 16:05:48 +03:00
for ( auto & elem : owner - > 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
2013-07-16 21:12:47 +03:00
if ( elem . currentFrame > = elem . maxFrame )
2011-12-22 16:05:19 +03:00
{
endAnim ( ) ;
break ;
}
else
{
2013-06-29 16:05:48 +03:00
elem . x + = dx ;
elem . y + = dy ;
2011-12-22 16:05:19 +03:00
}
}
}
}
void CSpellEffectAnimation : : endAnim ( )
{
CBattleAnimation : : endAnim ( ) ;
std : : vector < std : : list < BattleEffect > : : iterator > toDel ;
2013-06-29 16:05:48 +03:00
for ( auto it = owner - > battleEffects . begin ( ) ; it ! = owner - > battleEffects . end ( ) ; + + it )
2011-12-22 16:05:19 +03:00
{
if ( it - > effectID = = ID )
{
toDel . push_back ( it ) ;
}
}
2013-06-29 16:05:48 +03:00
for ( auto & elem : toDel )
2011-12-22 16:05:19 +03:00
{
2013-06-29 16:05:48 +03:00
delete elem - > anim ;
owner - > battleEffects . erase ( elem ) ;
2011-12-22 16:05:19 +03:00
}
delete this ;
2013-04-09 17:31:36 +03:00
}