X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fanim.c;h=2ef7872558b841ff080a4ee6902b6e2b13d54096;hp=fd6898eadf3fdce4ed53d13df18f7c72ad64e43b;hb=71c4b8d626b4a731a72840facb6bd548c7e33da9;hpb=f1f974498c1691431a5755d917f674c7cf56eb53 diff --git a/src/anim.c b/src/anim.c index fd6898ea..2ef78725 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" @@ -56,9 +58,10 @@ #define ANIM_STATE_RUNNING (1 << 2) /* values for global animation control */ -#define ANIM_START 0 -#define ANIM_CONTINUE 1 -#define ANIM_STOP 2 +#define ANIM_NO_ACTION 0 +#define ANIM_START 1 +#define ANIM_CONTINUE 2 +#define ANIM_STOP 3 struct GlobalAnimPartControlInfo @@ -68,6 +71,7 @@ struct GlobalAnimPartControlInfo int mode_nr; int sound; + int music; int graphic; struct GraphicInfo graphic_info; @@ -88,6 +92,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; @@ -171,6 +181,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]; @@ -182,6 +194,8 @@ static int anim_class_game_modes[NUM_ANIM_CLASSES]; static int anim_status_last = GAME_MODE_DEFAULT; static int anim_classes_last = ANIM_CLASS_NONE; +static boolean drawing_to_fading_buffer = FALSE; + /* ========================================================================= */ /* generic animation frame calculation */ @@ -329,6 +343,7 @@ static void InitToonControls() { struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; int sound = SND_UNDEFINED; + int music = MUS_UNDEFINED; int graphic = IMG_TOON_1 + i; int control = graphic; @@ -336,6 +351,7 @@ static void InitToonControls() 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]; @@ -367,7 +383,7 @@ void InitGlobalAnimControls() { int i, m, a, p; int mode_nr, anim_nr, part_nr; - int sound, graphic, control; + int sound, music, graphic, control; anim_sync_frame = 0; @@ -414,6 +430,7 @@ void InitGlobalAnimControls() struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; sound = global_anim_info[a].sound[p][m]; + music = global_anim_info[a].music[p][m]; graphic = global_anim_info[a].graphic[p][m]; control = global_anim_info[ctrl_id].graphic[p][m]; @@ -435,6 +452,7 @@ void InitGlobalAnimControls() 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]; @@ -511,10 +529,25 @@ void InitGlobalAnimations() InitGlobalAnimControls(); } -void DrawGlobalAnimationsExt(int drawing_stage) +void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage) { + Bitmap *fade_bitmap = + (drawing_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source : + drawing_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL); + int game_mode_anim_action[NUM_GAME_MODES]; int mode_nr; + if (!setup.toons) + return; + + if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1 && + drawing_target == DRAW_TO_SCREEN) + DoAnimationExt(); + + // always start with reliable default values (no animation actions) + for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) + game_mode_anim_action[mode_nr] = ANIM_NO_ACTION; + if (global.anim_status != anim_status_last) { boolean before_fading = (global.anim_status == GAME_MODE_PSEUDO_FADING); @@ -522,19 +555,22 @@ void DrawGlobalAnimationsExt(int drawing_stage) int anim_classes_next = game_mode_anim_classes[global.anim_status_next]; int i; + if (drawing_target == DRAW_TO_FADE_TARGET) + after_fading = TRUE; + // ---------- part 1 ------------------------------------------------------ // start or stop global animations by change of game mode // (special handling of animations for "current screen" and "all screens") // stop animations for last screen - HandleGlobalAnim(ANIM_STOP, anim_status_last); + game_mode_anim_action[anim_status_last] = ANIM_STOP; // start animations for current screen - HandleGlobalAnim(ANIM_START, global.anim_status); + game_mode_anim_action[global.anim_status] = ANIM_START; // start animations for all screens after loading new artwork set if (anim_status_last == GAME_MODE_LOADING) - HandleGlobalAnim(ANIM_START, GAME_MODE_DEFAULT); + game_mode_anim_action[GAME_MODE_DEFAULT] = ANIM_START; // ---------- part 2 ------------------------------------------------------ // start or stop global animations by change of animation class @@ -549,30 +585,54 @@ void DrawGlobalAnimationsExt(int drawing_stage) // stop animations for changed screen class before fading to new screen if (before_fading && anim_class_last && !anim_class_next) - HandleGlobalAnim(ANIM_STOP, anim_class_game_mode); + game_mode_anim_action[anim_class_game_mode] = ANIM_STOP; // start animations for changed screen class after fading to new screen if (after_fading && !anim_class_last && anim_class_next) - HandleGlobalAnim(ANIM_START, anim_class_game_mode); + game_mode_anim_action[anim_class_game_mode] = ANIM_START; } - if (after_fading) - anim_classes_last = anim_classes_next; + if (drawing_target == DRAW_TO_SCREEN) + { + if (after_fading) + anim_classes_last = anim_classes_next; + + anim_status_last = global.anim_status; - anim_status_last = global.anim_status; + // start or stop animations determined to be started or stopped above + for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) + if (game_mode_anim_action[mode_nr] != ANIM_NO_ACTION) + HandleGlobalAnim(game_mode_anim_action[mode_nr], mode_nr); + } + else if (drawing_target == DRAW_TO_FADE_TARGET) + { + drawing_to_fading_buffer = TRUE; + + // start animations determined to be (temporary) started above + for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) + if (game_mode_anim_action[mode_nr] == ANIM_START) + HandleGlobalAnim(ANIM_START, mode_nr); + } } - if (!setup.toons || global.anim_status == GAME_MODE_LOADING) + if (global.anim_status == GAME_MODE_LOADING) return; - if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1) - DoAnimationExt(); - for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) { struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr]; int anim_nr; + // when preparing source fading buffer, only draw animations to be stopped + if (drawing_target == DRAW_TO_FADE_SOURCE && + game_mode_anim_action[mode_nr] != ANIM_STOP) + continue; + + // when preparing target fading buffer, only draw animations to be started + if (drawing_target == DRAW_TO_FADE_TARGET && + game_mode_anim_action[mode_nr] != ANIM_START) + continue; + #if 0 if (mode_nr != GFX_SPECIAL_ARG_DEFAULT && mode_nr != game_status) @@ -655,16 +715,36 @@ void DrawGlobalAnimationsExt(int drawing_stage) src_x += cut_x; src_y += cut_y; - BlitToScreenMasked(src_bitmap, src_x, src_y, width, height, + if (drawing_target == DRAW_TO_SCREEN) + BlitToScreenMasked(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); } } } + + if (drawing_target == DRAW_TO_FADE_TARGET) + { + // stop animations determined to be (temporary) started above + for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) + if (game_mode_anim_action[mode_nr] == ANIM_START) + HandleGlobalAnim(ANIM_STOP, mode_nr); + + drawing_to_fading_buffer = FALSE; + } } -void DrawGlobalAnimations(int drawing_stage) +void DrawGlobalAnimations(int drawing_target, int drawing_stage) { - DrawGlobalAnimationsExt(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) @@ -730,7 +810,7 @@ boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part) return changed; } -void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part) +static void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part) { int sound = part->sound; @@ -748,12 +828,12 @@ void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part) PlaySound(sound); #if 0 - printf("::: PLAY %d.%d.%d: %d\n", + printf("::: PLAY SOUND %d.%d.%d: %d\n", part->anim_nr, part->nr, part->mode_nr, sound); #endif } -void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part) +static void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part) { int sound = part->sound; @@ -763,11 +843,98 @@ void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part) StopSound(sound); #if 0 - printf("::: STOP %d.%d.%d: %d\n", + printf("::: STOP SOUND %d.%d.%d: %d\n", part->anim_nr, part->nr, part->mode_nr, sound); #endif } +static void PlayGlobalAnimMusic(struct GlobalAnimPartControlInfo *part) +{ + int music = part->music; + + if (music == MUS_UNDEFINED) + return; + + if (!setup.sound_music) + return; + + PlayMusic(music); + +#if 0 + printf("::: PLAY MUSIC %d.%d.%d: %d\n", + part->anim_nr, part->nr, part->mode_nr, music); +#endif +} + +static void StopGlobalAnimMusic(struct GlobalAnimPartControlInfo *part) +{ + int music = part->music; + + if (music == MUS_UNDEFINED) + return; + + StopMusic(); + +#if 0 + printf("::: STOP MUSIC %d.%d.%d: %d\n", + part->anim_nr, part->nr, part->mode_nr, music); +#endif +} + +static void PlayGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part) +{ + // when drawing animations to fading buffer, do not play sounds or music + if (drawing_to_fading_buffer) + return; + + PlayGlobalAnimSound(part); + PlayGlobalAnimMusic(part); +} + +static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part) +{ + StopGlobalAnimSound(part); + StopGlobalAnimMusic(part); +} + +static boolean isClickablePart(struct GlobalAnimPartControlInfo *part) +{ + struct GraphicInfo *c = &part->control_info; + + return (c->init_event & ANIM_EVENT_CLICK || + c->anim_event & ANIM_EVENT_CLICK); +} + +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; @@ -779,6 +946,11 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) if (state & ANIM_STATE_RESTART) { + // when drawing animations to fading buffer, only start fixed animations + if (drawing_to_fading_buffer && (c->x == ARG_UNDEFINED_VALUE || + c->y == ARG_UNDEFINED_VALUE)) + return ANIM_STATE_INACTIVE; + ResetDelayCounterExt(&part->step_delay, anim_sync_frame); part->init_delay_counter = @@ -787,6 +959,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); @@ -863,8 +1038,32 @@ 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) - PlayGlobalAnimSound(part); + if (part->init_delay_counter == 0 && + part->init_event_state == ANIM_EVENT_NONE) + PlayGlobalAnimSoundAndMusic(part); + } + + part->clickable = isClickablePart(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) @@ -872,22 +1071,32 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) part->init_delay_counter--; if (part->init_delay_counter == 0) - PlayGlobalAnimSound(part); + { + 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; + // 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) { - StopGlobalAnimSound(part); + StopGlobalAnimSoundAndMusic(part); part->post_delay_counter = (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random)); @@ -906,7 +1115,9 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) if (part->anim_delay_counter == 0) { - StopGlobalAnimSound(part); + part->anim_event_state = ANIM_EVENT_NONE; + + StopGlobalAnimSoundAndMusic(part); part->post_delay_counter = (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random)); @@ -1001,7 +1212,7 @@ void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) int i; for (i = 0; i < num_parts; i++) - StopGlobalAnimSound(&anim->part[i]); + StopGlobalAnimSoundAndMusic(&anim->part[i]); } return; @@ -1140,8 +1351,97 @@ static void DoAnimationExt() for (i = 0; i < NUM_GAME_MODES; i++) HandleGlobalAnim(ANIM_CONTINUE, i); -#if 1 +#if 0 // force screen redraw in next frame to continue drawing global animations 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 < NUM_GLOBAL_ANIMS_AND_TOONS; anim_nr++) + { + struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr]; + int part_nr; + + for (part_nr = 0; part_nr < NUM_GLOBAL_ANIM_PARTS_AND_TOONS; 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 < NUM_GLOBAL_ANIMS_AND_TOONS; anim_nr++) + { + struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr]; + int part_nr; + + for (part_nr = 0; part_nr < NUM_GLOBAL_ANIM_PARTS_AND_TOONS; part_nr++) + { + struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; + + part->clicked = FALSE; + + if (part->clickable && isClickedPart(part, mx, my, clicked)) + any_part_clicked = part->clicked = TRUE; + } + } + } + + 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; +}