diff --git a/inc/sprite_eng.h b/inc/sprite_eng.h
index ee55f4cc..bdeeaf64 100644
--- a/inc/sprite_eng.h
+++ b/inc/sprite_eng.h
@@ -44,8 +44,8 @@
#define SPR_FLAG_INSERT_HEAD 0x4000
/**
* \brief
- * Disable animation auto loop..
- * By default animation always restart fater the last frame has been played.
+ * Disable animation auto loop.
+ * By default animation always restart after the last frame has been played.
* This flag prevent the animation to restart and so the animation end on the last frame forever (see #SPR_getAnimationDone(..))
*/
#define SPR_FLAG_DISABLE_ANIMATION_LOOP 0x2000
@@ -844,8 +844,8 @@ bool SPR_getAutoAnimation(Sprite* sprite);
void SPR_setAnimationLoop(Sprite* sprite, bool value);
/**
* \brief
- * Return TRUE if the sprite reached the last frame of the current animation.
- * When auto animation is enabled (see SPR_setAutoAnimation(..)) the function returns TRUE only when we reach
+ * Returns TRUE if the sprite reached the end of the current animation.
+ * When auto animation is enabled (see SPR_setAutoAnimation(..)) the function returns TRUE only when we reached
* the last *tick* of the last animation frame.
* When auto animation is disabled the function returns TRUE as soon we are on last animation frame.
*
diff --git a/inc/sprite_eng_legacy.h b/inc/sprite_eng_legacy.h
index 38895598..87509681 100644
--- a/inc/sprite_eng_legacy.h
+++ b/inc/sprite_eng_legacy.h
@@ -44,8 +44,8 @@
#define SPR_FLAG_INSERT_HEAD 0x4000
/**
* \brief
- * Disable animation auto loop..
- * By default animation always restart fater the last frame has been played.
+ * Disable animation auto loop.
+ * By default animation always restart after the last frame has been played.
* This flag prevent the animation to restart and so the animation end on the last frame forever (see #SPR_getAnimationDone(..))
*/
#define SPR_FLAG_DISABLE_ANIMATION_LOOP 0x2000
@@ -837,8 +837,8 @@ bool SPR_getAutoAnimation(Sprite* sprite);
void SPR_setAnimationLoop(Sprite* sprite, bool value);
/**
* \brief
- * Return TRUE if the sprite reached the last frame of the current animation.
- * When auto animation is enabled (see SPR_setAutoAnimation(..)) the function returns TRUE only when we reach
+ * Returns TRUE if the sprite reached the end of the current animation.
+ * When auto animation is enabled (see SPR_setAutoAnimation(..)) the function returns TRUE only when we reached
* the last *tick* of the last animation frame.
* When auto animation is disabled the function returns TRUE as soon we are on last animation frame.
*
diff --git a/lib/libmd.a b/lib/libmd.a
index 537f7e1d..feb9f4ff 100644
Binary files a/lib/libmd.a and b/lib/libmd.a differ
diff --git a/lib/libmd_debug.a b/lib/libmd_debug.a
index 724db483..feb9f4ff 100644
Binary files a/lib/libmd_debug.a and b/lib/libmd_debug.a differ
diff --git a/src/sprite_eng.c b/src/sprite_eng.c
index f018ed88..58188393 100644
--- a/src/sprite_eng.c
+++ b/src/sprite_eng.c
@@ -47,6 +47,9 @@
#define NEED_UPDATE 0x000F
+#define STATE_ANIMATION_DONE 0x0010
+
+
// shared from vdp_spr.c unit
extern void logVDPSprite(u16 index);
@@ -1147,6 +1150,8 @@ void SPR_nextFrame(Sprite* sprite)
// loop
frameInd = anim->loop;
+ // set animation done state (allows SPR_isAnimationDone(..) to correctly report state when called from frame change callback)
+ sprite->status |= STATE_ANIMATION_DONE;
}
// set new frame
@@ -1203,8 +1208,10 @@ bool SPR_isAnimationDone(Sprite* sprite)
// for debug
checkSpriteValid(sprite, "SPR_isAnimationDone");
- // last tick on last animation frame (use <= 1 so it also works when AutoAnimation is disabled)
- return (sprite->timer <= 1) && (sprite->frameInd == (sprite->animation->numFrame - 1));
+ // check for animation done state (mainly used for frame change callback) or
+ return (sprite->status & STATE_ANIMATION_DONE) ||
+ // if we are on last tick from last frame (if auto animation is disabled then only test for last frame)
+ ((sprite->frameInd == (sprite->animation->numFrame - 1)) && ((sprite->timer == 1) || (sprite->timer == -1)));
}
bool SPR_setVRAMTileIndex(Sprite* sprite, s16 value)
@@ -1937,6 +1944,9 @@ static u16 updateFrame(Sprite* sprite, u16 status)
// set frame
sprite->frame = frame;
+ // init timer for this frame *before* frame change callback so it can modify change it if needed.
+ if (SPR_getAutoAnimation(sprite))
+ sprite->timer = frame->timer;
// frame change event handler defined ? --> call it
if (sprite->onFrameChange)
@@ -1945,16 +1955,6 @@ static u16 updateFrame(Sprite* sprite, u16 status)
sprite->status = status;
sprite->onFrameChange(sprite);
status = sprite->status;
-
- // init timer for this frame *after* callback call and only if auto animation is enabled and timer was not manually changed in callback
- if (sprite->timer == 0)
- sprite->timer = frame->timer;
- }
- else
- {
- // init timer for this frame *after* callback call to allow SPR_isAnimationDone(..) to correctly report TRUE when animation is done in the callbacnk
- if (SPR_getAutoAnimation(sprite))
- sprite->timer = frame->timer;
}
// require tile data upload
@@ -1964,8 +1964,8 @@ static u16 updateFrame(Sprite* sprite, u16 status)
if (status & SPR_FLAG_AUTO_VISIBILITY)
status |= NEED_VISIBILITY_UPDATE;
- // frame update done
- status &= ~NEED_FRAME_UPDATE;
+ // frame update done, also clear ANIMATION_DONE state
+ status &= ~(NEED_FRAME_UPDATE | STATE_ANIMATION_DONE);
END_PROFIL(PROFIL_UPDATE_FRAME)
diff --git a/src/sprite_eng_legacy.c b/src/sprite_eng_legacy.c
index 47c45d32..dd65544d 100644
--- a/src/sprite_eng_legacy.c
+++ b/src/sprite_eng_legacy.c
@@ -49,6 +49,8 @@
#define NEED_UPDATE 0x001F
+#define STATE_ANIMATION_DONE 0x0020
+
// shared from vdp_spr.c unit
extern void logVDPSprite(u16 index);
@@ -1161,6 +1163,8 @@ void SPR_nextFrame(Sprite* sprite)
// loop
frameInd = anim->loop;
+ // set animation done state (allows SPR_isAnimationDone(..) to correctly report state when called from frame change callback)
+ sprite->status |= STATE_ANIMATION_DONE;
}
// set new frame
@@ -1221,8 +1225,10 @@ bool SPR_isAnimationDone(Sprite* sprite)
if (!isSpriteValid(sprite, "SPR_isAnimationDone"))
return FALSE;
- // last tick on last animation frame (use <= 1 so it also works when AutoAnimation is disabled)
- return (sprite->timer <= 1) && (sprite->frameInd == (sprite->animation->numFrame - 1));
+ // check for animation done state (mainly used for frame change callback) or
+ return (sprite->status & STATE_ANIMATION_DONE) ||
+ // if we are on last tick from last frame (if auto animation is disabled then only test for last frame)
+ ((sprite->frameInd == (sprite->animation->numFrame - 1)) && ((sprite->timer == 1) || (sprite->timer == -1)));
}
@@ -1895,6 +1901,9 @@ static u16 updateFrame(Sprite* sprite, u16 status)
sprite->lastNumSprite = currentNumSprite;
// set frame
sprite->frame = frame;
+ // init timer for this frame *before* frame change callback so it can modify change it if needed.
+ if (SPR_getAutoAnimation(sprite))
+ sprite->timer = frame->timer;
// frame change event handler defined ? --> call it
if (sprite->onFrameChange)
@@ -1905,10 +1914,6 @@ static u16 updateFrame(Sprite* sprite, u16 status)
status = sprite->status;
}
- // init timer for this frame *after* calling callback (this allows SPR_isAnimationDone(..) to correctly report TRUE when animation is done)
- if (SPR_getAutoAnimation(sprite))
- sprite->timer = frame->timer;
-
// require tile data upload
if (status & SPR_FLAG_AUTO_TILE_UPLOAD)
status |= NEED_TILES_UPLOAD;
@@ -1916,8 +1921,8 @@ static u16 updateFrame(Sprite* sprite, u16 status)
if (status & SPR_FLAG_AUTO_VISIBILITY)
status |= NEED_VISIBILITY_UPDATE;
- // frame update done
- status &= ~NEED_FRAME_UPDATE;
+ // frame update done, also clear ANIMATION_DONE state
+ status &= ~(NEED_FRAME_UPDATE | STATE_ANIMATION_DONE);
END_PROFIL(PROFIL_UPDATE_FRAME)