Decouple Animations from Gamelogi (Smooth Animations for skipped Frames).
NewPlrAnim: Use default arguments instead of overloads
StartPlrHit: Fix skippedAnimationFrames - Frames starts with 1
Add missing comment for StartPlrHit
Fix GotHit-Animation: Skipping Frames corrected and adjusted _pAnimGameTicksSinceSequenceStarted for animations that don't start with a additional tick.
Thanks @StephenCWills for the gothit skipping frame calculation logic :-)
Update StartWalk: calculated numSkippedFrames in own line.
Co-authored-by: Anders Jenbo <anders@jenbo.dk>
StartPlrHit: always initialize skippedAnimationFrames
Co-authored-by: Anders Jenbo <anders@jenbo.dk>
Update nthread_GetProgressToNextGameTick comment
Co-authored-by: Anders Jenbo <anders@jenbo.dk>
fix spelling "lenght" instead of "length"
Update NewPlrAnim comment
Co-authored-by: Anders Jenbo <anders@jenbo.dk>
GetFrameToUseForPlayerRendering: avoid one "else"
intskippedAnimationFrames=1;// Every Attack start with Frame 2. Because ProcessPlayerAnimation is called after StartAttack and its increases the AnimationFrame.
intskippedAnimationFrames=1;// Every Attack start with Frame 2. Because ProcessPlayerAnimation is called after StartRangeAttack and its increases the AnimationFrame.
intskippedAnimationFrames=0;// Block can start with Frame 1 if Player 2 hits Player 1. In this case Player 1 will not call again ProcessPlayerAnimation.
if(plr[pnum]._pIFlags&ISPL_FASTBLOCK){
skippedAnimationFrames=(plr[pnum]._pBFrames-1);// ISPL_FASTBLOCK means there is only one AnimationFrame.
intskippedAnimationFrames=0;// GotHit can start with Frame 1. GotHit can for example be called in ProcessMonsters() and this is after ProcessPlayers().
if((plr[pnum]._pIFlags&ZenFlags)==ZenFlags){// if multiple hitrecovery modes are present the skipping of frames can go so far, that they skip frames that would skip. so the additional skipping thats skipped. that means we can't add the different modes together.
// - if no frame-skipping is required and so we have exactly one Animationframe per GameTick (_pAnimUsedNumFrames = 0)
// or
// - if we load from a savegame where the new variables are not stored (we don't want to break savegame compatiblity because of smoother rendering of one animation)
if(pPlayer->_pAnimNumSkippedFrames<=0)
returnpPlayer->_pAnimFrame;
// After an attack hits (_pAFNum or _pSFNum) it can be canceled or another attack can be queued and this means the animation is canceled.
// In normal attacks frame skipping always happens before the attack actual hit.
// This has the advantage that the sword or bow always points to the enemy when the hit happens (_pAFNum or _pSFNum).
// Our distribution logic must also regard this behaviour, so we are not allowed to distribute the skipped animations after the actual hit (_pAnimStopDistributingAfterFrame).
floattotalGameTicksForCurrentAnimationSequence=progressToNextGameTick+(float)pPlayer->_pAnimGameTicksSinceSequenceStarted;// we don't use the processed game ticks alone but also the fragtion of the next game tick (if a rendering happens between game ticks). This helps to smooth the animations.
floatgameTickModifier=(float)animationMaxGameTickets/(float)(relevantAnimationLength-pPlayer->_pAnimNumSkippedFrames);// if we skipped Frames we need to expand the GameTicks to make one GameTick for this Animation "faster"
intabsolutAnimationFrame=1+(int)(totalGameTicksForCurrentAnimationSequence*gameTickModifier);// 1 added for rounding reasons. float to int cast always truncate.
if(absolutAnimationFrame>relevantAnimationLength)// this can happen if we are at the last frame and the next game tick is due (nthread_GetProgressToNextGameTick returns 1.0f)
returnrelevantAnimationLength;
if(absolutAnimationFrame<=0){
SDL_Log("GetFrameToUseForPlayerRendering: Calculated an invalid Animation Frame");