+ int viewport_x;
+ int viewport_y;
+ int viewport_width;
+ int viewport_height;
+ boolean changed = FALSE;
+
+ if (part->last_anim_status == global.anim_status)
+ return FALSE;
+
+ part->last_anim_status = global.anim_status;
+
+ part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
+
+ if (part->control_info.class == get_hash_from_key("window") ||
+ part->control_info.class == get_hash_from_key("border"))
+ {
+ viewport_x = 0;
+ viewport_y = 0;
+ viewport_width = WIN_XSIZE;
+ viewport_height = WIN_YSIZE;
+
+ part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
+ }
+ else if (part->control_info.class == get_hash_from_key("door_1"))
+ {
+ viewport_x = DX;
+ viewport_y = DY;
+ viewport_width = DXSIZE;
+ viewport_height = DYSIZE;
+ }
+ else if (part->control_info.class == get_hash_from_key("door_2"))
+ {
+ viewport_x = VX;
+ viewport_y = VY;
+ viewport_width = VXSIZE;
+ viewport_height = VYSIZE;
+ }
+ else // default: "playfield"
+ {
+ viewport_x = REAL_SX;
+ viewport_y = REAL_SY;
+ viewport_width = FULL_SXSIZE;
+ viewport_height = FULL_SYSIZE;
+ }
+
+ if (viewport_x != part->viewport_x ||
+ viewport_y != part->viewport_y ||
+ viewport_width != part->viewport_width ||
+ viewport_height != part->viewport_height)
+ {
+ part->viewport_x = viewport_x;
+ part->viewport_y = viewport_y;
+ part->viewport_width = viewport_width;
+ part->viewport_height = viewport_height;
+
+ changed = TRUE;
+ }
+
+ return changed;
+}
+
+int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
+{
+ struct GraphicInfo *g = &part->graphic_info;
+ struct GraphicInfo *c = &part->control_info;
+ boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
+
+ if (viewport_changed)
+ state |= ANIM_STATE_RESTART;
+
+ if (state & ANIM_STATE_RESTART)
+ {
+ ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
+
+ part->init_delay_counter =
+ (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
+
+ part->anim_delay_counter =
+ (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
+
+ part->initial_anim_sync_frame =
+ (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
+
+ if (c->direction & MV_HORIZONTAL)
+ {
+ int pos_bottom = part->viewport_height - g->height;
+
+ if (c->position == POS_TOP)
+ part->y = 0;
+ else if (c->position == POS_UPPER)
+ part->y = GetSimpleRandom(pos_bottom / 2);
+ else if (c->position == POS_MIDDLE)
+ part->y = pos_bottom / 2;
+ else if (c->position == POS_LOWER)
+ part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
+ else if (c->position == POS_BOTTOM)
+ part->y = pos_bottom;
+ else
+ part->y = GetSimpleRandom(pos_bottom);
+
+ if (c->direction == MV_RIGHT)
+ {
+ part->step_xoffset = c->step_offset;
+ part->x = -g->width + part->step_xoffset;
+ }
+ else
+ {
+ part->step_xoffset = -c->step_offset;
+ part->x = part->viewport_width + part->step_xoffset;
+ }
+
+ part->step_yoffset = 0;
+ }
+ else if (c->direction & MV_VERTICAL)
+ {
+ int pos_right = part->viewport_width - g->width;
+
+ if (c->position == POS_LEFT)
+ part->x = 0;
+ else if (c->position == POS_RIGHT)
+ part->x = pos_right;
+ else
+ part->x = GetSimpleRandom(pos_right);
+
+ if (c->direction == MV_DOWN)
+ {
+ part->step_yoffset = c->step_offset;
+ part->y = -g->height + part->step_yoffset;
+ }
+ else
+ {
+ part->step_yoffset = -c->step_offset;
+ part->y = part->viewport_height + part->step_yoffset;
+ }
+
+ part->step_xoffset = 0;
+ }
+ else
+ {
+ part->x = 0;
+ part->y = 0;
+
+ part->step_xoffset = 0;
+ part->step_yoffset = 0;
+ }
+
+ if (c->x != ARG_UNDEFINED_VALUE)
+ part->x = c->x;
+ if (c->y != ARG_UNDEFINED_VALUE)
+ part->y = c->y;
+
+ if (c->step_xoffset != ARG_UNDEFINED_VALUE)
+ part->step_xoffset = c->step_xoffset;
+ if (c->step_yoffset != ARG_UNDEFINED_VALUE)
+ part->step_yoffset = c->step_yoffset;
+ }
+
+ if (part->init_delay_counter > 0)
+ {
+ part->init_delay_counter--;
+
+ return ANIM_STATE_WAITING;
+ }
+
+ 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;
+
+ if (part->anim_delay_counter > 0)
+ {
+ part->anim_delay_counter--;
+
+ if (part->anim_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 | ANIM_STATE_RUNNING;
+ }
+ }
+
+ if (part->post_delay_counter > 0)
+ {
+ part->post_delay_counter--;
+
+ if (part->post_delay_counter == 0)
+ return ANIM_STATE_RESTART;
+
+ return ANIM_STATE_WAITING;
+ }
+
+ if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
+ anim_sync_frame))
+ return ANIM_STATE_RUNNING;
+
+#if 0
+ {
+ static unsigned int last_counter = -1;
+ unsigned int counter = Counter();
+
+ printf("::: NEXT ANIM PART [%d, %d]\n",
+ anim_sync_frame, counter - last_counter);
+
+ last_counter = counter;
+ }
+#endif
+
+ part->x += part->step_xoffset;
+ part->y += part->step_yoffset;
+
+ return ANIM_STATE_RUNNING;
+}
+
+void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
+{
+ struct GlobalAnimPartControlInfo *part;
+ struct GraphicInfo *c = &anim->control_info;
+
+#if 0
+ printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
+ anim->mode_nr, anim->nr, anim->num_parts);
+ printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
+#endif
+
+#if 0
+ printf("::: %s(%d): %d, %d, %d [%d]\n",
+ (action == ANIM_START ? "ANIM_START" :
+ action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
+ action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
+ anim->nr,
+ anim->state & ANIM_STATE_RESTART,
+ anim->state & ANIM_STATE_WAITING,
+ anim->state & ANIM_STATE_RUNNING,
+ anim->num_parts);
+#endif
+
+ switch (action)
+ {
+ case ANIM_START:
+ anim->state = ANIM_STATE_RESTART;
+ anim->part_counter = 0;
+ anim->active_part_nr = 0;
+
+ break;
+
+ case ANIM_CONTINUE:
+ if (anim->state == ANIM_STATE_INACTIVE)
+ return;
+
+ break;
+
+ case ANIM_STOP:
+ anim->state = ANIM_STATE_INACTIVE;
+
+ return;
+
+ default:
+ break;
+ }
+
+ if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
+ {
+ int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
+ int i;
+
+#if 0
+ printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
+ anim->mode_nr, anim->nr, num_parts);
+#endif
+
+ for (i = 0; i < num_parts; i++)
+ {
+ part = &anim->part[i];
+
+ switch (action)
+ {
+ case ANIM_START:
+ anim->state = ANIM_STATE_RUNNING;
+ part->state = ANIM_STATE_RESTART;
+
+ break;
+
+ case ANIM_CONTINUE:
+ if (part->state == ANIM_STATE_INACTIVE)
+ continue;
+
+ break;
+
+ case ANIM_STOP:
+ part->state = ANIM_STATE_INACTIVE;
+
+ continue;
+
+ default:
+ break;
+ }
+
+ 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;
+ }
+
+ if (anim->state & ANIM_STATE_RESTART) // directly after restart
+ anim->active_part_nr = getGlobalAnimationPart(anim);
+
+ part = &anim->part[anim->active_part_nr];
+
+ part->state = ANIM_STATE_RUNNING;
+
+ anim->state = HandleGlobalAnim_Part(part, anim->state);
+
+ if (anim->state & ANIM_STATE_RESTART)
+ anim->part_counter++;
+
+ // 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;
+}
+
+void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
+{
+ int i;
+
+#if 0
+ printf("::: HandleGlobalAnim_Mode: %d => %d\n",
+ ctrl->nr, ctrl->num_anims);
+#endif
+
+ for (i = 0; i < ctrl->num_anims; i++)
+ HandleGlobalAnim_Main(&ctrl->anim[i], action);
+}
+
+static void HandleGlobalAnim(int action, int game_mode)
+{
+#if 0
+ printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
+#endif
+
+ HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);