diff --git a/Source/engine/animationinfo.cpp b/Source/engine/animationinfo.cpp index f81548235..91c32af6b 100644 --- a/Source/engine/animationinfo.cpp +++ b/Source/engine/animationinfo.cpp @@ -54,7 +54,7 @@ int AnimationInfo::GetFrameToUseForRendering() const void AnimationInfo::SetNewAnimation(uint8_t *pData, int numberOfFrames, int delayLen, AnimationDistributionFlags flags /*= AnimationDistributionFlags::None*/, int numSkippedFrames /*= 0*/, int distributeFramesBeforeFrame /*= 0*/) { - if (pData == this->pData && distributeFramesBeforeFrame != 0 && NumberOfFrames == numberOfFrames && CurrentFrame >= distributeFramesBeforeFrame && CurrentFrame != NumberOfFrames) { + if ((flags & AnimationDistributionFlags::RepeatedAction) == AnimationDistributionFlags::RepeatedAction && distributeFramesBeforeFrame != 0 && NumberOfFrames == numberOfFrames && CurrentFrame >= distributeFramesBeforeFrame && CurrentFrame != NumberOfFrames) { // We showed the same Animation (for example a melee attack) before but truncated the Animation. // So now we should add them back to the new Animation. This increases the speed of the current Animation but the game logic/ticks isn't affected. SkippedFramesFromPreviousAnimation = NumberOfFrames - CurrentFrame; diff --git a/Source/engine/animationinfo.h b/Source/engine/animationinfo.h index e250d5b1a..ba708a2d8 100644 --- a/Source/engine/animationinfo.h +++ b/Source/engine/animationinfo.h @@ -23,6 +23,10 @@ enum AnimationDistributionFlags : uint8_t { * @brief Delay of last Frame is ignored (for example, because only Frame and not delay is checked in game_logic) */ SkipsDelayOfLastFrame = 1 << 1, + /** + * @brief Repeated Animation (for example same player melee attack, that can be repeated directly after hit frame and doesn't need to show all animation frames) + */ + RepeatedAction = 1 << 2, }; /* diff --git a/Source/player.cpp b/Source/player.cpp index 427542a93..7e8022197 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -1489,7 +1489,10 @@ void StartAttack(int pnum, direction d) skippedAnimationFrames = 2; } - NewPlrAnim(pnum, plr[pnum]._pAAnim[d], plr[pnum]._pAFrames, 0, plr[pnum]._pAWidth, AnimationDistributionFlags::ProcessAnimationPending, skippedAnimationFrames, plr[pnum]._pAFNum); + auto animationFlags = AnimationDistributionFlags::ProcessAnimationPending; + if (plr[pnum]._pmode == PM_ATTACK) + animationFlags = static_cast(animationFlags | AnimationDistributionFlags::RepeatedAction); + NewPlrAnim(pnum, plr[pnum]._pAAnim[d], plr[pnum]._pAFrames, 0, plr[pnum]._pAWidth, animationFlags, skippedAnimationFrames, plr[pnum]._pAFNum); plr[pnum]._pmode = PM_ATTACK; FixPlayerLocation(pnum, d); SetPlayerOld(pnum); @@ -1517,7 +1520,10 @@ void StartRangeAttack(int pnum, direction d, int cx, int cy) } } - NewPlrAnim(pnum, plr[pnum]._pAAnim[d], plr[pnum]._pAFrames, 0, plr[pnum]._pAWidth, AnimationDistributionFlags::ProcessAnimationPending, skippedAnimationFrames, plr[pnum]._pAFNum); + auto animationFlags = AnimationDistributionFlags::ProcessAnimationPending; + if (plr[pnum]._pmode == PM_RATTACK) + animationFlags = static_cast(animationFlags | AnimationDistributionFlags::RepeatedAction); + NewPlrAnim(pnum, plr[pnum]._pAAnim[d], plr[pnum]._pAFrames, 0, plr[pnum]._pAWidth, animationFlags, skippedAnimationFrames, plr[pnum]._pAFNum); plr[pnum]._pmode = PM_RATTACK; FixPlayerLocation(pnum, d); @@ -1565,24 +1571,28 @@ void StartSpell(int pnum, direction d, int cx, int cy) } if (leveltype != DTYPE_TOWN) { + auto animationFlags = AnimationDistributionFlags::ProcessAnimationPending; + if (plr[pnum]._pmode == PM_SPELL) + animationFlags = static_cast(animationFlags | AnimationDistributionFlags::RepeatedAction); + switch (spelldata[plr[pnum]._pSpell].sType) { case STYPE_FIRE: if ((plr[pnum]._pGFXLoad & PFILE_FIRE) == 0) { LoadPlrGFX(pnum, PFILE_FIRE); } - NewPlrAnim(pnum, plr[pnum]._pFAnim[d], plr[pnum]._pSFrames, 0, plr[pnum]._pSWidth, AnimationDistributionFlags::ProcessAnimationPending, 0, plr[pnum]._pSFNum); + NewPlrAnim(pnum, plr[pnum]._pFAnim[d], plr[pnum]._pSFrames, 0, plr[pnum]._pSWidth, animationFlags, 0, plr[pnum]._pSFNum); break; case STYPE_LIGHTNING: if ((plr[pnum]._pGFXLoad & PFILE_LIGHTNING) == 0) { LoadPlrGFX(pnum, PFILE_LIGHTNING); } - NewPlrAnim(pnum, plr[pnum]._pLAnim[d], plr[pnum]._pSFrames, 0, plr[pnum]._pSWidth, AnimationDistributionFlags::ProcessAnimationPending, 0, plr[pnum]._pSFNum); + NewPlrAnim(pnum, plr[pnum]._pLAnim[d], plr[pnum]._pSFrames, 0, plr[pnum]._pSWidth, animationFlags, 0, plr[pnum]._pSFNum); break; case STYPE_MAGIC: if ((plr[pnum]._pGFXLoad & PFILE_MAGIC) == 0) { LoadPlrGFX(pnum, PFILE_MAGIC); } - NewPlrAnim(pnum, plr[pnum]._pTAnim[d], plr[pnum]._pSFrames, 0, plr[pnum]._pSWidth, AnimationDistributionFlags::ProcessAnimationPending, 0, plr[pnum]._pSFNum); + NewPlrAnim(pnum, plr[pnum]._pTAnim[d], plr[pnum]._pSFrames, 0, plr[pnum]._pSWidth, animationFlags, 0, plr[pnum]._pSFNum); break; } } diff --git a/test/animationinfo_test.cpp b/test/animationinfo_test.cpp index 3aaa65f77..538104958 100644 --- a/test/animationinfo_test.cpp +++ b/test/animationinfo_test.cpp @@ -275,7 +275,7 @@ TEST(AnimationInfo, AttackSwordWarriorRepeated) new RenderingData(0.3f, 10), // Start of repeated attack, cause plr[pnum].AnimInfo.CurrentFrame > plr[myplr]._pAFNum - new SetNewAnimationData(16, 0, AnimationDistributionFlags::ProcessAnimationPending, 0, 9), + new SetNewAnimationData(16, 0, static_cast(AnimationDistributionFlags::ProcessAnimationPending | AnimationDistributionFlags::RepeatedAction), 0, 9), // ProcessAnimation directly after StartAttack (in same GameTick). So we don't see any rendering before. new GameTickData(2, 0), new RenderingData(0.0f, 11),