diff --git a/src/fheroes2/ai/ai_hero_action.cpp b/src/fheroes2/ai/ai_hero_action.cpp index c8bebff6cc5..cdb3f970ff2 100644 --- a/src/fheroes2/ai/ai_hero_action.cpp +++ b/src/fheroes2/ai/ai_hero_action.cpp @@ -254,7 +254,7 @@ namespace if ( AIIsShowAnimationForHero( hero, AIGetAllianceColors() ) ) { Interface::AdventureMap::Get().getGameArea().SetCenter( hero.GetCenter() ); - hero.FadeOut(); + hero.FadeOut( Game::AIHeroAnimSpeedMultiplier() ); } hero.Scout( targetIndex ); @@ -264,7 +264,7 @@ namespace if ( AIIsShowAnimationForHero( hero, AIGetAllianceColors() ) ) { Interface::AdventureMap::Get().getGameArea().SetCenter( hero.GetCenter() ); - hero.FadeIn(); + hero.FadeIn( Game::AIHeroAnimSpeedMultiplier() ); } AI::Get().HeroesActionComplete( hero, targetIndex, hero.getObjectTypeUnderHero() ); @@ -283,8 +283,12 @@ namespace if ( playSound ) { AudioManager::PlaySound( M82::KILLFADE ); + + hero.FadeOut(); + } + else { + hero.FadeOut( Game::AIHeroAnimSpeedMultiplier() ); } - hero.FadeOut(); } hero.Dismiss( reason ); @@ -847,7 +851,7 @@ namespace if ( AIIsShowAnimationForHero( hero, AIGetAllianceColors() ) ) { // AI-controlled hero cannot activate Stone Liths from the same tile, but should move to this tile from some // other tile first, so there is no need to re-center the game area on the hero before his disappearance - hero.FadeOut(); + hero.FadeOut( Game::AIHeroAnimSpeedMultiplier() ); } hero.Scout( indexTo ); @@ -856,7 +860,7 @@ namespace if ( AIIsShowAnimationForHero( hero, AIGetAllianceColors() ) ) { Interface::AdventureMap::Get().getGameArea().SetCenter( hero.GetCenter() ); - hero.FadeIn(); + hero.FadeIn( Game::AIHeroAnimSpeedMultiplier() ); } hero.ActionNewPosition( false ); @@ -912,7 +916,7 @@ namespace if ( AIIsShowAnimationForHero( hero, AIGetAllianceColors() ) ) { // AI-controlled hero cannot activate Whirlpool from the same tile, but should move to this tile from some // other tile first, so there is no need to re-center the game area on the hero before his disappearance - hero.FadeOut(); + hero.FadeOut( Game::AIHeroAnimSpeedMultiplier() ); } hero.Scout( indexTo ); @@ -923,7 +927,7 @@ namespace if ( AIIsShowAnimationForHero( hero, AIGetAllianceColors() ) ) { Interface::AdventureMap::Get().getGameArea().SetCenter( hero.GetCenter() ); - hero.FadeIn(); + hero.FadeIn( Game::AIHeroAnimSpeedMultiplier() ); } hero.ActionNewPosition( false ); @@ -1573,7 +1577,7 @@ namespace if ( AIIsShowAnimationForHero( hero, AIGetAllianceColors() ) ) { Interface::AdventureMap::Get().getGameArea().SetCenter( hero.GetCenter() ); - hero.FadeOut( offset ); + hero.FadeOut( Game::AIHeroAnimSpeedMultiplier(), offset ); } hero.Scout( dst_index ); @@ -1616,7 +1620,7 @@ namespace if ( AIIsShowAnimationForHero( hero, AIGetAllianceColors() ) ) { Interface::AdventureMap::Get().getGameArea().SetCenter( prevPos ); - hero.FadeIn( offset ); + hero.FadeIn( Game::AIHeroAnimSpeedMultiplier(), offset ); } hero.ActionNewPosition( true ); @@ -2057,7 +2061,7 @@ namespace AI bool resetHeroSprite = false; if ( heroAnimationFrameCount > 0 ) { - const int32_t heroMovementSkipValue = Game::AIHeroAnimSkip(); + const int32_t heroMovementSkipValue = Game::AIHeroAnimSpeedMultiplier(); gameArea.ShiftCenter( { heroAnimationOffset.x * heroMovementSkipValue, heroAnimationOffset.y * heroMovementSkipValue } ); gameArea.SetRedraw(); @@ -2087,7 +2091,7 @@ namespace AI else { const fheroes2::Point movement( hero.MovementDirection() ); if ( movement != fheroes2::Point() ) { // don't waste resources for no movement - const int32_t heroMovementSkipValue = Game::AIHeroAnimSkip(); + const int32_t heroMovementSkipValue = Game::AIHeroAnimSpeedMultiplier(); heroAnimationOffset = movement; gameArea.ShiftCenter( movement ); @@ -2136,7 +2140,7 @@ namespace AI if ( AIIsShowAnimationForHero( hero, AIGetAllianceColors() ) ) { Interface::AdventureMap::Get().getGameArea().SetCenter( hero.GetCenter() ); - hero.FadeOut(); + hero.FadeOut( Game::AIHeroAnimSpeedMultiplier() ); } hero.Scout( targetIndex ); @@ -2147,7 +2151,7 @@ namespace AI if ( AIIsShowAnimationForHero( hero, AIGetAllianceColors() ) ) { Interface::AdventureMap::Get().getGameArea().SetCenter( hero.GetCenter() ); - hero.FadeIn(); + hero.FadeIn( Game::AIHeroAnimSpeedMultiplier() ); } hero.ActionNewPosition( false ); diff --git a/src/fheroes2/game/game_delays.cpp b/src/fheroes2/game/game_delays.cpp index cafa72a5e46..1cc0b605f3a 100644 --- a/src/fheroes2/game/game_delays.cpp +++ b/src/fheroes2/game/game_delays.cpp @@ -204,13 +204,17 @@ void Game::UpdateGameSpeed() delays[BATTLE_FLAGS_DELAY].setDelay( static_cast( 250 * adjustedIdleAnimationSpeed ) ); } -int Game::HumanHeroAnimSkip() +int Game::HumanHeroAnimSpeedMultiplier() { + assert( humanHeroMultiplier > 0 ); + return humanHeroMultiplier; } -int Game::AIHeroAnimSkip() +int Game::AIHeroAnimSpeedMultiplier() { + assert( aiHeroMultiplier > 0 ); + return aiHeroMultiplier; } diff --git a/src/fheroes2/game/game_delays.h b/src/fheroes2/game/game_delays.h index 6fd49dfee7a..937d73ee6c8 100644 --- a/src/fheroes2/game/game_delays.h +++ b/src/fheroes2/game/game_delays.h @@ -86,8 +86,11 @@ namespace Game uint32_t ApplyBattleSpeed( uint32_t delay ); - int HumanHeroAnimSkip(); - int AIHeroAnimSkip(); + // Returns the animation speed multiplier for a human-controlled hero. + int HumanHeroAnimSpeedMultiplier(); + + // Returns the animation speed multiplier for an AI-controlled hero. + int AIHeroAnimSpeedMultiplier(); // Returns true if every of delay type has passed. bool hasEveryDelayPassed( const std::vector & delayTypes ); diff --git a/src/fheroes2/game/game_startgame.cpp b/src/fheroes2/game/game_startgame.cpp index c0daccfd49a..9c2c8f5c23a 100644 --- a/src/fheroes2/game/game_startgame.cpp +++ b/src/fheroes2/game/game_startgame.cpp @@ -1233,7 +1233,7 @@ fheroes2::GameMode Interface::AdventureMap::HumanTurn( const bool isload ) if ( hero ) { bool resetHeroSprite = false; if ( heroAnimationFrameCount > 0 ) { - const int32_t heroMovementSkipValue = Game::HumanHeroAnimSkip(); + const int32_t heroMovementSkipValue = Game::HumanHeroAnimSpeedMultiplier(); _gameArea.ShiftCenter( { heroAnimationOffset.x * heroMovementSkipValue, heroAnimationOffset.y * heroMovementSkipValue } ); _gameArea.SetRedraw(); @@ -1279,7 +1279,7 @@ fheroes2::GameMode Interface::AdventureMap::HumanTurn( const bool isload ) // Do not generate a frame as we are going to do it later. Interface::AdventureMap::RedrawLocker redrawLocker( Interface::AdventureMap::Get() ); - const int32_t heroMovementSkipValue = Game::HumanHeroAnimSkip(); + const int32_t heroMovementSkipValue = Game::HumanHeroAnimSpeedMultiplier(); heroAnimationOffset = movement; _gameArea.ShiftCenter( movement ); diff --git a/src/fheroes2/heroes/heroes.h b/src/fheroes2/heroes/heroes.h index 48f9741bfb4..628d8fcbeaf 100644 --- a/src/fheroes2/heroes/heroes.h +++ b/src/fheroes2/heroes/heroes.h @@ -524,8 +524,23 @@ class Heroes final : public HeroBase, public ColorBase fheroes2::Point getCurrentPixelOffset() const; - void FadeOut( const fheroes2::Point & offset = fheroes2::Point() ) const; - void FadeIn( const fheroes2::Point & offset = fheroes2::Point() ) const; + // Performs a hero fade-out animation with the given speed multiplier and an optional offset + void FadeOut( const int animSpeedMultiplier, const fheroes2::Point & offset = fheroes2::Point() ) const; + + // Performs a hero fade-in animation with the given speed multiplier and an optional offset + void FadeIn( const int animSpeedMultiplier, const fheroes2::Point & offset = fheroes2::Point() ) const; + + // Performs a hero fade-out animation with an optional offset at the lowest possible speed + void FadeOut( const fheroes2::Point & offset = fheroes2::Point() ) const + { + FadeOut( 1, offset ); + } + + // Performs a hero fade-in animation with an optional offset at the lowest possible speed + void FadeIn( const fheroes2::Point & offset = fheroes2::Point() ) const + { + FadeIn( 1, offset ); + } void Scout( const int tileIndex ) const; int GetScoutingDistance() const; diff --git a/src/fheroes2/heroes/heroes_move.cpp b/src/fheroes2/heroes/heroes_move.cpp index 533ae470526..1753c421c5b 100644 --- a/src/fheroes2/heroes/heroes_move.cpp +++ b/src/fheroes2/heroes/heroes_move.cpp @@ -483,71 +483,71 @@ fheroes2::Point Heroes::getCurrentPixelOffset() const return realOffset; } -void Heroes::FadeOut( const fheroes2::Point & offset ) const +void Heroes::FadeOut( const int animSpeedMultiplier, const fheroes2::Point & offset /* = fheroes2::Point() */ ) const { - if ( !isInVisibleMapArea() ) + assert( animSpeedMultiplier > 0 ); + + if ( !isInVisibleMapArea() ) { return; + } Interface::AdventureMap & iface = Interface::AdventureMap::Get(); Interface::GameArea & gamearea = iface.getGameArea(); - int multiplier = std::max( offset.x < 0 ? -offset.x : offset.x, offset.y < 0 ? -offset.y : offset.y ); - if ( multiplier < 1 ) - multiplier = 1; - - const bool offsetScreen = offset.x != 0 || offset.y != 0; - fheroes2::Display & display = fheroes2::Display::instance(); LocalEvent & le = LocalEvent::Get(); - _alphaValue = 255 - 8 * multiplier; - const std::vector delayTypes = { Game::HEROES_FADE_DELAY }; - while ( le.HandleEvents( Game::isDelayNeeded( delayTypes ) ) && _alphaValue > 0 ) { - if ( Game::validateAnimationDelay( Game::HEROES_FADE_DELAY ) ) { - if ( offsetScreen ) { - gamearea.ShiftCenter( offset ); - } + _alphaValue = 255; - iface.redraw( Interface::REDRAW_GAMEAREA ); + while ( le.HandleEvents( Game::isDelayNeeded( { Game::HEROES_FADE_DELAY } ) ) && _alphaValue > 0 ) { + if ( !Game::validateAnimationDelay( Game::HEROES_FADE_DELAY ) ) { + continue; + } - display.render(); - _alphaValue -= 8 * multiplier; + if ( offset.x != 0 || offset.y != 0 ) { + gamearea.ShiftCenter( offset ); } + + _alphaValue = std::max( 0, _alphaValue - 8 * animSpeedMultiplier ); + + iface.redraw( Interface::REDRAW_GAMEAREA ); + + display.render(); } _alphaValue = 255; } -void Heroes::FadeIn( const fheroes2::Point & offset ) const +void Heroes::FadeIn( const int animSpeedMultiplier, const fheroes2::Point & offset /* = fheroes2::Point() */ ) const { - if ( !isInVisibleMapArea() ) + assert( animSpeedMultiplier > 0 ); + + if ( !isInVisibleMapArea() ) { return; + } Interface::AdventureMap & iface = Interface::AdventureMap::Get(); Interface::GameArea & gamearea = iface.getGameArea(); - int multiplier = std::max( offset.x < 0 ? -offset.x : offset.x, offset.y < 0 ? -offset.y : offset.y ); - if ( multiplier < 1 ) - multiplier = 1; - - const bool offsetScreen = offset.x != 0 || offset.y != 0; - fheroes2::Display & display = fheroes2::Display::instance(); LocalEvent & le = LocalEvent::Get(); - _alphaValue = 8 * multiplier; - const std::vector delayTypes = { Game::HEROES_FADE_DELAY }; - while ( le.HandleEvents( Game::isDelayNeeded( delayTypes ) ) && _alphaValue < 250 ) { - if ( Game::validateAnimationDelay( Game::HEROES_FADE_DELAY ) ) { - if ( offsetScreen ) { - gamearea.ShiftCenter( offset ); - } + _alphaValue = 0; - iface.redraw( Interface::REDRAW_GAMEAREA ); + while ( le.HandleEvents( Game::isDelayNeeded( { Game::HEROES_FADE_DELAY } ) ) && _alphaValue < 255 ) { + if ( !Game::validateAnimationDelay( Game::HEROES_FADE_DELAY ) ) { + continue; + } - display.render(); - _alphaValue += 8 * multiplier; + if ( offset.x != 0 || offset.y != 0 ) { + gamearea.ShiftCenter( offset ); } + + _alphaValue = std::min( _alphaValue + 8 * animSpeedMultiplier, 255 ); + + iface.redraw( Interface::REDRAW_GAMEAREA ); + + display.render(); } _alphaValue = 255;