X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fanim.c;h=b566bddcbc27132d458a1dbf28519f4b3aba6d78;hp=b9ea8becc2a44d2b84ea4e32e8424a95e96a7e87;hb=e14d20831f1abdbcfccd5c8afcaf715e3849f468;hpb=b9cb8d24d6b501098d657ec1715574b2718c02f6 diff --git a/src/anim.c b/src/anim.c index b9ea8bec..b566bddc 100644 --- a/src/anim.c +++ b/src/anim.c @@ -9,6 +9,8 @@ // anim.c // ============================================================================ +#include "libgame/libgame.h" + #include "anim.h" #include "main.h" #include "tools.h" @@ -64,10 +66,15 @@ struct GlobalAnimPartControlInfo { + int old_nr; // position before mapping animation parts linearly + int old_anim_nr; // position before mapping animations linearly + int nr; int anim_nr; int mode_nr; + boolean is_base; // animation part is base/main/default animation part + int sound; int music; int graphic; @@ -90,6 +97,12 @@ struct GlobalAnimPartControlInfo int anim_delay_counter; int post_delay_counter; + boolean init_event_state; + boolean anim_event_state; + + boolean clickable; + boolean clicked; + int drawing_stage; int state; @@ -106,11 +119,12 @@ struct GlobalAnimMainControlInfo struct GraphicInfo control_info; - int num_parts; + int num_parts; // number of animation parts, but without base part + int num_parts_all; // number of animation parts, including base part int part_counter; int active_part_nr; - boolean has_base; + boolean has_base; // animation has base/main/default animation part int init_delay_counter; @@ -173,6 +187,8 @@ struct AnimClassGameMode /* forward declaration for internal use */ static void HandleGlobalAnim(int, int); static void DoAnimationExt(void); +static void ResetGlobalAnim_Clickable(); +static void ResetGlobalAnim_Clicked(); static struct GlobalAnimControlInfo global_anim_ctrl[NUM_GAME_MODES]; @@ -318,6 +334,7 @@ static void InitToonControls() anim->control_info = graphic_info[control]; anim->num_parts = 0; + anim->num_parts_all = 0; anim->part_counter = 0; anim->active_part_nr = 0; @@ -340,9 +357,13 @@ static void InitToonControls() part->nr = part_nr; part->anim_nr = anim_nr; part->mode_nr = mode_nr; + + part->is_base = FALSE; + part->sound = sound; part->music = music; part->graphic = graphic; + part->graphic_info = graphic_info[graphic]; part->control_info = graphic_info[control]; @@ -363,6 +384,8 @@ static void InitToonControls() part->last_anim_status = -1; anim->num_parts++; + anim->num_parts_all++; + part_nr++; } @@ -404,6 +427,7 @@ void InitGlobalAnimControls() anim->control_info = graphic_info[control]; anim->num_parts = 0; + anim->num_parts_all = 0; anim->part_counter = 0; anim->active_part_nr = 0; @@ -438,12 +462,17 @@ void InitGlobalAnimControls() m, a, p, mode_nr, anim_nr, part_nr, sound); #endif + part->old_nr = p; + part->old_anim_nr = a; + part->nr = part_nr; part->anim_nr = anim_nr; part->mode_nr = mode_nr; + part->sound = sound; part->music = music; part->graphic = graphic; + part->graphic_info = graphic_info[graphic]; part->control_info = graphic_info[control]; @@ -455,13 +484,19 @@ void InitGlobalAnimControls() part->state = ANIM_STATE_INACTIVE; part->last_anim_status = -1; + anim->num_parts_all++; + if (p < GLOBAL_ANIM_ID_PART_BASE) { + part->is_base = FALSE; + anim->num_parts++; part_nr++; } else { + part->is_base = TRUE; + anim->base = *part; anim->has_base = TRUE; } @@ -663,6 +698,10 @@ void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage) int cut_y = 0; int sync_frame; int frame; + void (*blit_bitmap)(Bitmap *, Bitmap *, int, int, int, int, int, int) = + (g->draw_masked ? BlitBitmapMasked : BlitBitmap); + void (*blit_screen)(Bitmap *, int, int, int, int, int, int) = + (g->draw_masked ? BlitToScreenMasked : BlitToScreen); if (!(part->state & ANIM_STATE_RUNNING)) continue; @@ -706,11 +745,11 @@ void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage) src_y += cut_y; if (drawing_target == DRAW_TO_SCREEN) - BlitToScreenMasked(src_bitmap, src_x, src_y, width, height, - dst_x, dst_y); + blit_screen(src_bitmap, src_x, src_y, width, height, + dst_x, dst_y); else - BlitBitmapMasked(src_bitmap, fade_bitmap, src_x, src_y, width, height, - dst_x, dst_y); + blit_bitmap(src_bitmap, fade_bitmap, src_x, src_y, width, height, + dst_x, dst_y); } } } @@ -728,7 +767,13 @@ void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage) void DrawGlobalAnimations(int drawing_target, int drawing_stage) { + if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1) + ResetGlobalAnim_Clickable(); + DrawGlobalAnimationsExt(drawing_target, drawing_stage); + + if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_2) + ResetGlobalAnim_Clicked(); } boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part) @@ -881,6 +926,59 @@ static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part) StopGlobalAnimMusic(part); } +static boolean matchesAnimEventMask(int bits, int mask) +{ + return (bits & (mask & ANIM_EVENT_CLICK_ANIM_ALL) && + bits & (mask & ANIM_EVENT_CLICK_PART_ALL)); +} + +static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask) +{ + struct GraphicInfo *c = &part->control_info; + + boolean clickable_self = FALSE; + boolean clickable_triggered = FALSE; + + if (mask & ANIM_EVENT_CLICK_SELF) + clickable_self = (c->init_event & ANIM_EVENT_CLICK_SELF || + c->anim_event & ANIM_EVENT_CLICK_SELF); + + clickable_triggered = (matchesAnimEventMask(c->init_event, mask) || + matchesAnimEventMask(c->anim_event, mask)); + + return (clickable_self || clickable_triggered); +} + +static boolean isClickedPart(struct GlobalAnimPartControlInfo *part, + int mx, int my, boolean clicked) +{ + struct GraphicInfo *g = &part->graphic_info; + int part_x = part->viewport_x + part->x; + int part_y = part->viewport_y + part->y; + int part_width = g->width; + int part_height = g->height; + + // check if mouse click was detected at all + if (!clicked) + return FALSE; + + // check if mouse click is inside the animation part's viewport + if (mx < part->viewport_x || + mx >= part->viewport_x + part->viewport_width || + my < part->viewport_y || + my >= part->viewport_y + part->viewport_height) + return FALSE; + + // check if mouse click is inside the animation part's graphic + if (mx < part_x || + mx >= part_x + part_width || + my < part_y || + my >= part_y + part_height) + return FALSE; + + return TRUE; +} + int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) { struct GraphicInfo *g = &part->graphic_info; @@ -905,6 +1003,9 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) part->anim_delay_counter = (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random)); + part->init_event_state = c->init_event; + part->anim_event_state = c->anim_event; + part->initial_anim_sync_frame = (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter); @@ -981,26 +1082,61 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) if (c->step_yoffset != ARG_UNDEFINED_VALUE) part->step_yoffset = c->step_yoffset; - if (part->init_delay_counter == 0) + if (part->init_delay_counter == 0 && + part->init_event_state == ANIM_EVENT_NONE) PlayGlobalAnimSoundAndMusic(part); } + if (part->clicked && + part->init_event_state != ANIM_EVENT_NONE) + { + if (part->initial_anim_sync_frame > 0) + part->initial_anim_sync_frame -= part->init_delay_counter - 1; + + part->init_delay_counter = 1; + part->init_event_state = ANIM_EVENT_NONE; + + part->clicked = FALSE; + } + + if (part->clicked && + part->anim_event_state != ANIM_EVENT_NONE) + { + part->anim_delay_counter = 1; + part->anim_event_state = ANIM_EVENT_NONE; + + part->clicked = FALSE; + } + if (part->init_delay_counter > 0) { part->init_delay_counter--; if (part->init_delay_counter == 0) + { + part->init_event_state = ANIM_EVENT_NONE; + PlayGlobalAnimSoundAndMusic(part); + } return ANIM_STATE_WAITING; } + if (part->init_event_state != ANIM_EVENT_NONE) + return ANIM_STATE_WAITING; + + // animation part is now running/visible and therefore clickable + part->clickable = TRUE; + // 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)) { + // do not wait for "anim" events for off-screen animations + part->anim_event_state = ANIM_EVENT_NONE; + // do not stop animation before "anim" or "post" counter are finished if (part->anim_delay_counter == 0 && part->post_delay_counter == 0) @@ -1024,6 +1160,8 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) if (part->anim_delay_counter == 0) { + part->anim_event_state = ANIM_EVENT_NONE; + StopGlobalAnimSoundAndMusic(part); part->post_delay_counter = @@ -1263,3 +1401,144 @@ static void DoAnimationExt() redraw_mask = REDRAW_ALL; #endif } + +static void InitGlobalAnim_Clickable() +{ + int mode_nr; + + for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) + { + struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr]; + int anim_nr; + + for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++) + { + struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr]; + int part_nr; + + for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++) + { + struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; + + part->clickable = FALSE; + } + } + } +} + +static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked) +{ + boolean any_part_clicked = FALSE; + int mode_nr; + + for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) + { + struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr]; + int anim_nr; + + for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++) + { + struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr]; + int part_nr; + + for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++) + { + struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; + + if (!clicked) + { + part->clicked = FALSE; + + continue; + } + + if (part->clickable && + isClickedPart(part, mx, my, clicked)) + { +#if 0 + printf("::: %d.%d CLICKED\n", anim_nr, part_nr); +#endif + + if (isClickablePart(part, ANIM_EVENT_CLICK_SELF)) + any_part_clicked = part->clicked = TRUE; + + // check if this click is defined to trigger other animations + int old_anim_nr = part->old_anim_nr; + int old_part_nr = part->old_nr; + int mask = ANIM_EVENT_CLICK_ANIM_1 << old_anim_nr; + + if (part->is_base) + mask |= ANIM_EVENT_CLICK_PART_ALL; + else + mask |= ANIM_EVENT_CLICK_PART_1 << old_part_nr; + + int anim2_nr; + + for (anim2_nr = 0; anim2_nr < ctrl->num_anims; anim2_nr++) + { + struct GlobalAnimMainControlInfo *anim2 = &ctrl->anim[anim2_nr]; + int part2_nr; + + for (part2_nr = 0; part2_nr < anim2->num_parts_all; part2_nr++) + { + struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr]; + + if (isClickablePart(part2, mask)) + any_part_clicked = part2->clicked = TRUE; + +#if 0 + struct GraphicInfo *c = &part2->control_info; + + printf("::: - %d.%d: 0x%08x, 0x%08x [0x%08x]", + anim2_nr, part2_nr, c->init_event, c->anim_event, mask); + + if (isClickablePart(part2, mask)) + printf(" <--- TRIGGERED BY %d.%d", + anim_nr, part_nr); + + printf("\n"); +#endif + } + } + } + } + } + } + + return any_part_clicked; +} + +static void ResetGlobalAnim_Clickable() +{ + InitGlobalAnim_Clickable(); +} + +static void ResetGlobalAnim_Clicked() +{ + InitGlobalAnim_Clicked(-1, -1, FALSE); +} + +boolean HandleGlobalAnimClicks(int mx, int my, int button) +{ + static boolean click_consumed = FALSE; + static int last_button = 0; + boolean press_event; + boolean release_event; + boolean click_consumed_current = click_consumed; + + /* check if button state has changed since last invocation */ + press_event = (button != 0 && last_button == 0); + release_event = (button == 0 && last_button != 0); + last_button = button; + + if (press_event) + { + click_consumed = InitGlobalAnim_Clicked(mx, my, TRUE); + click_consumed_current = click_consumed; + } + + if (release_event) + click_consumed = FALSE; + + return click_consumed_current; +}