int init_delay_counter;
int state;
+
+ int last_state, last_active_part_nr;
};
struct GlobalAnimControlInfo
return part_nr;
}
+static int compareGlobalAnimPartControlInfo(const void *obj1, const void *obj2)
+{
+ const struct GlobalAnimPartControlInfo *o1 =
+ (struct GlobalAnimPartControlInfo *)obj1;
+ const struct GlobalAnimPartControlInfo *o2 =
+ (struct GlobalAnimPartControlInfo *)obj2;
+ int compare_result;
+
+ if (o1->control_info.draw_order != o2->control_info.draw_order)
+ compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
+ else
+ compare_result = o1->nr - o2->nr;
+
+ return compare_result;
+}
+
+static int compareGlobalAnimMainControlInfo(const void *obj1, const void *obj2)
+{
+ const struct GlobalAnimMainControlInfo *o1 =
+ (struct GlobalAnimMainControlInfo *)obj1;
+ const struct GlobalAnimMainControlInfo *o2 =
+ (struct GlobalAnimMainControlInfo *)obj2;
+ int compare_result;
+
+ if (o1->control_info.draw_order != o2->control_info.draw_order)
+ compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
+ else
+ compare_result = o1->nr - o2->nr;
+
+ return compare_result;
+}
+
static void PrepareBackbuffer()
{
if (game_status != GAME_MODE_PLAYING)
InitToonControls();
+ /* sort all animations according to draw_order and animation number */
+ for (m = 0; m < NUM_GAME_MODES; m++)
+ {
+ struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[m];
+
+ /* sort all main animations for this game mode */
+ qsort(ctrl->anim, ctrl->num_anims,
+ sizeof(struct GlobalAnimMainControlInfo),
+ compareGlobalAnimMainControlInfo);
+
+ for (a = 0; a < ctrl->num_anims; a++)
+ {
+ struct GlobalAnimMainControlInfo *anim = &ctrl->anim[a];
+
+ /* sort all animation parts for this main animation */
+ qsort(anim->part, anim->num_parts,
+ sizeof(struct GlobalAnimPartControlInfo),
+ compareGlobalAnimPartControlInfo);
+ }
+ }
+
for (i = 0; i < NUM_GAME_MODES; i++)
game_mode_anim_classes[i] = ANIM_CLASS_NONE;
for (i = 0; game_mode_anim_classes_list[i].game_mode != -1; i++)
else if (part->y > part->viewport_height - g->height)
height -= (part->y - (part->viewport_height - g->height));
+ if (width <= 0 || height <= 0)
+ continue;
+
dst_x += part->viewport_x;
dst_y += part->viewport_y;
return ANIM_STATE_WAITING;
}
+ // check if moving animation has left the visible screen area
if ((part->x <= -g->width && part->step_xoffset <= 0) ||
(part->x >= part->viewport_width && part->step_xoffset >= 0) ||
(part->y <= -g->height && part->step_yoffset <= 0) ||
(part->y >= part->viewport_height && part->step_yoffset >= 0))
- return ANIM_STATE_RESTART;
+ {
+ // do not stop animation before "anim" or "post" counter are finished
+ if (part->anim_delay_counter == 0 &&
+ part->post_delay_counter == 0)
+ {
+ part->post_delay_counter =
+ (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
+
+ if (part->post_delay_counter > 0)
+ return ANIM_STATE_RUNNING;
+
+ return ANIM_STATE_RESTART;
+ }
+ }
if (part->anim_delay_counter > 0)
{
if (part->post_delay_counter > 0)
return ANIM_STATE_RUNNING;
+ // additional state "RUNNING" required to not skip drawing last frame
return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
}
}
{
struct GlobalAnimPartControlInfo *part;
struct GraphicInfo *c = &anim->control_info;
- boolean skip = FALSE;
+ int state, active_part_nr;
#if 0
printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
switch (action)
{
case ANIM_START:
- anim->state = ANIM_STATE_RESTART;
+ anim->state = anim->last_state = ANIM_STATE_RESTART;
+ anim->active_part_nr = anim->last_active_part_nr = 0;
anim->part_counter = 0;
- anim->active_part_nr = 0;
- skip = TRUE;
break;
case ANIM_CONTINUE:
if (anim->state == ANIM_STATE_INACTIVE)
- skip = TRUE;
+ return;
+
+ anim->state = anim->last_state;
+ anim->active_part_nr = anim->last_active_part_nr;
break;
case ANIM_STOP:
anim->state = ANIM_STATE_INACTIVE;
- skip = TRUE;
- break;
+ return;
default:
break;
case ANIM_START:
anim->state = ANIM_STATE_RUNNING;
part->state = ANIM_STATE_RESTART;
- skip = TRUE;
break;
case ANIM_CONTINUE:
if (part->state == ANIM_STATE_INACTIVE)
- skip = TRUE;
+ continue;
break;
case ANIM_STOP:
part->state = ANIM_STATE_INACTIVE;
- skip = TRUE;
- break;
+ continue;
default:
break;
}
- if (skip)
- continue;
-
part->state = HandleGlobalAnim_Part(part, part->state);
+
+ // when animation mode is "once", stop after animation was played once
+ if (c->anim_mode & ANIM_ONCE &&
+ part->state & ANIM_STATE_RESTART)
+ part->state = ANIM_STATE_INACTIVE;
}
- return;
- }
+ anim->last_state = anim->state;
+ anim->last_active_part_nr = anim->active_part_nr;
- if (skip)
return;
+ }
if (anim->state & ANIM_STATE_RESTART) // directly after restart
anim->active_part_nr = getGlobalAnimationPart(anim);
if (anim->state & ANIM_STATE_RESTART)
anim->part_counter++;
- if (anim->part_counter == anim->num_parts &&
- c->anim_mode & ANIM_ONCE)
+ // when animation mode is "once", stop after all animations were played once
+ if (c->anim_mode & ANIM_ONCE &&
+ anim->part_counter == anim->num_parts)
anim->state = ANIM_STATE_INACTIVE;
+
+ state = anim->state;
+ active_part_nr = anim->active_part_nr;
+
+ // while the animation parts are pausing (waiting or inactive), play the base
+ // (main) animation; this corresponds to the "boring player animation" logic
+ // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!)
+ if (anim->has_base)
+ {
+ if (anim->state == ANIM_STATE_WAITING ||
+ anim->state == ANIM_STATE_INACTIVE)
+ {
+ anim->active_part_nr = anim->num_parts; // part nr of base animation
+ part = &anim->part[anim->active_part_nr];
+
+ if (anim->state != anim->last_state)
+ part->state = ANIM_STATE_RESTART;
+
+ anim->state = ANIM_STATE_RUNNING;
+ part->state = HandleGlobalAnim_Part(part, part->state);
+ }
+ }
+
+ anim->last_state = state;
+ anim->last_active_part_nr = active_part_nr;
}
void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)