X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fanim.c;h=48393eb3141f320c38f1f58fe9c88afd7676a651;hp=7464637dd3dc9443eae91b2bcdeeb833d8c2dd41;hb=897c46a2720672a49ce6d0803b08eed23fd2dd90;hpb=b270fc80ba831c22d288ce68c2dde728c97d2333 diff --git a/src/anim.c b/src/anim.c index 7464637d..48393eb3 100644 --- a/src/anim.c +++ b/src/anim.c @@ -14,13 +14,16 @@ #include "anim.h" #include "main.h" #include "tools.h" +#include "files.h" +#include "events.h" +#include "screens.h" -/* values for global toon animation definition */ +// values for global toon animation definition #define NUM_GLOBAL_TOON_ANIMS 1 #define NUM_GLOBAL_TOON_PARTS MAX_NUM_TOONS -/* values for global animation definition (including toons) */ +// values for global animation definition (including toons) #define NUM_GLOBAL_ANIMS_AND_TOONS (NUM_GLOBAL_ANIMS + \ NUM_GLOBAL_TOON_ANIMS) #define NUM_GLOBAL_ANIM_PARTS_AND_TOONS MAX(NUM_GLOBAL_ANIM_PARTS_ALL, \ @@ -29,35 +32,45 @@ #define ANIM_CLASS_BIT_TITLE_INITIAL 0 #define ANIM_CLASS_BIT_TITLE 1 #define ANIM_CLASS_BIT_MAIN 2 -#define ANIM_CLASS_BIT_SUBMENU 3 -#define ANIM_CLASS_BIT_MENU 4 -#define ANIM_CLASS_BIT_TOONS 5 +#define ANIM_CLASS_BIT_SCORES 3 +#define ANIM_CLASS_BIT_SUBMENU 4 +#define ANIM_CLASS_BIT_MENU 5 +#define ANIM_CLASS_BIT_TOONS 6 +#define ANIM_CLASS_BIT_NO_TITLE 7 -#define NUM_ANIM_CLASSES 6 +#define NUM_ANIM_CLASSES 8 #define ANIM_CLASS_NONE 0 #define ANIM_CLASS_TITLE_INITIAL (1 << ANIM_CLASS_BIT_TITLE_INITIAL) #define ANIM_CLASS_TITLE (1 << ANIM_CLASS_BIT_TITLE) #define ANIM_CLASS_MAIN (1 << ANIM_CLASS_BIT_MAIN) +#define ANIM_CLASS_SCORES (1 << ANIM_CLASS_BIT_SCORES) #define ANIM_CLASS_SUBMENU (1 << ANIM_CLASS_BIT_SUBMENU) #define ANIM_CLASS_MENU (1 << ANIM_CLASS_BIT_MENU) #define ANIM_CLASS_TOONS (1 << ANIM_CLASS_BIT_TOONS) +#define ANIM_CLASS_NO_TITLE (1 << ANIM_CLASS_BIT_NO_TITLE) -#define ANIM_CLASS_TOONS_MENU_MAIN (ANIM_CLASS_TOONS | \ - ANIM_CLASS_MENU | \ - ANIM_CLASS_MAIN) +#define ANIM_CLASS_TOONS_SCORES (ANIM_CLASS_TOONS | \ + ANIM_CLASS_SCORES | \ + ANIM_CLASS_NO_TITLE) -#define ANIM_CLASS_TOONS_MENU_SUBMENU (ANIM_CLASS_TOONS | \ - ANIM_CLASS_MENU | \ - ANIM_CLASS_SUBMENU) +#define ANIM_CLASS_TOONS_MENU_MAIN (ANIM_CLASS_TOONS | \ + ANIM_CLASS_MENU | \ + ANIM_CLASS_MAIN | \ + ANIM_CLASS_NO_TITLE) -/* values for global animation states */ +#define ANIM_CLASS_TOONS_MENU_SUBMENU (ANIM_CLASS_TOONS | \ + ANIM_CLASS_MENU | \ + ANIM_CLASS_SUBMENU | \ + ANIM_CLASS_NO_TITLE) + +// values for global animation states #define ANIM_STATE_INACTIVE 0 #define ANIM_STATE_RESTART (1 << 0) #define ANIM_STATE_WAITING (1 << 1) #define ANIM_STATE_RUNNING (1 << 2) -/* values for global animation control */ +// values for global animation control #define ANIM_NO_ACTION 0 #define ANIM_START 1 #define ANIM_CONTINUE 2 @@ -165,7 +178,10 @@ struct GameModeAnimClass { GAME_MODE_SETUP, ANIM_CLASS_TOONS_MENU_SUBMENU }, { GAME_MODE_PSEUDO_MAINONLY, ANIM_CLASS_TOONS_MENU_MAIN }, { GAME_MODE_PSEUDO_TYPENAME, ANIM_CLASS_TOONS_MENU_MAIN }, - { GAME_MODE_SCORES, ANIM_CLASS_TOONS }, + { GAME_MODE_PSEUDO_SCORESOLD, ANIM_CLASS_TOONS_SCORES }, + { GAME_MODE_PSEUDO_SCORESNEW, ANIM_CLASS_TOONS_SCORES }, + { GAME_MODE_EDITOR, ANIM_CLASS_NO_TITLE }, + { GAME_MODE_PLAYING, ANIM_CLASS_NO_TITLE }, { -1, -1 } }; @@ -179,18 +195,20 @@ struct AnimClassGameMode { ANIM_CLASS_BIT_TITLE_INITIAL, GAME_MODE_TITLE_INITIAL }, { ANIM_CLASS_BIT_TITLE, GAME_MODE_TITLE }, { ANIM_CLASS_BIT_MAIN, GAME_MODE_MAIN }, + { ANIM_CLASS_BIT_SCORES, GAME_MODE_SCORES }, { ANIM_CLASS_BIT_SUBMENU, GAME_MODE_PSEUDO_SUBMENU }, { ANIM_CLASS_BIT_MENU, GAME_MODE_PSEUDO_MENU }, { ANIM_CLASS_BIT_TOONS, GAME_MODE_PSEUDO_TOONS }, + { ANIM_CLASS_BIT_NO_TITLE, GAME_MODE_PSEUDO_NO_TITLE }, { -1, -1 } }; -/* forward declaration for internal use */ +// forward declaration for internal use static void HandleGlobalAnim(int, int); static void DoAnimationExt(void); -static void ResetGlobalAnim_Clickable(); -static void ResetGlobalAnim_Clicked(); +static void ResetGlobalAnim_Clickable(void); +static void ResetGlobalAnim_Clicked(void); static struct GlobalAnimControlInfo global_anim_ctrl[NUM_GAME_MODES]; @@ -199,15 +217,16 @@ static unsigned int anim_sync_frame = 0; static int game_mode_anim_classes[NUM_GAME_MODES]; static int anim_class_game_modes[NUM_ANIM_CLASSES]; +static int anim_status_last_before_fading = GAME_MODE_DEFAULT; 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 */ -/* ========================================================================= */ +// ============================================================================ +// generic animation frame calculation +// ============================================================================ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame, int sync_frame) @@ -216,34 +235,34 @@ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame, sync_frame += start_frame * delay; - if (mode & ANIM_LOOP) /* looping animation */ + if (mode & ANIM_LOOP) // looping animation { frame = (sync_frame % (delay * num_frames)) / delay; } - else if (mode & ANIM_LINEAR) /* linear (non-looping) animation */ + else if (mode & ANIM_LINEAR) // linear (non-looping) animation { frame = sync_frame / delay; if (frame > num_frames - 1) frame = num_frames - 1; } - else if (mode & ANIM_PINGPONG) /* oscillate (border frames once) */ + else if (mode & ANIM_PINGPONG) // oscillate (border frames once) { int max_anim_frames = (num_frames > 1 ? 2 * num_frames - 2 : 1); frame = (sync_frame % (delay * max_anim_frames)) / delay; frame = (frame < num_frames ? frame : max_anim_frames - frame); } - else if (mode & ANIM_PINGPONG2) /* oscillate (border frames twice) */ + else if (mode & ANIM_PINGPONG2) // oscillate (border frames twice) { int max_anim_frames = 2 * num_frames; frame = (sync_frame % (delay * max_anim_frames)) / delay; frame = (frame < num_frames ? frame : max_anim_frames - frame - 1); } - else if (mode & ANIM_RANDOM) /* play frames in random order */ + else if (mode & ANIM_RANDOM) // play frames in random order { - /* note: expect different frames for the same delay cycle! */ + // note: expect different frames for the same delay cycle! if (gfx.anim_random_frame < 0) frame = GetSimpleRandom(num_frames); @@ -255,16 +274,16 @@ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame, frame = sync_frame % num_frames; } - if (mode & ANIM_REVERSE) /* use reverse animation direction */ + if (mode & ANIM_REVERSE) // use reverse animation direction frame = num_frames - frame - 1; return frame; } -/* ========================================================================= */ -/* global animation functions */ -/* ========================================================================= */ +// ============================================================================ +// global animation functions +// ============================================================================ static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim) { @@ -315,7 +334,7 @@ static int compareGlobalAnimMainControlInfo(const void *obj1, const void *obj2) return compare_result; } -static void InitToonControls() +static void InitToonControls(void) { int mode_nr_toons = GAME_MODE_PSEUDO_TOONS; struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr_toons]; @@ -397,7 +416,7 @@ static void InitToonControls() ctrl->num_anims++; } -void InitGlobalAnimControls() +static void InitGlobalAnimControls(void) { int i, m, a, p; int mode_nr, anim_nr, part_nr; @@ -520,12 +539,12 @@ void InitGlobalAnimControls() InitToonControls(); - /* sort all animations according to draw_order and animation number */ + // 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 */ + // sort all main animations for this game mode qsort(ctrl->anim, ctrl->num_anims, sizeof(struct GlobalAnimMainControlInfo), compareGlobalAnimMainControlInfo); @@ -534,7 +553,7 @@ void InitGlobalAnimControls() { struct GlobalAnimMainControlInfo *anim = &ctrl->anim[a]; - /* sort all animation parts for this main animation */ + // sort all animation parts for this main animation qsort(anim->part, anim->num_parts, sizeof(struct GlobalAnimPartControlInfo), compareGlobalAnimPartControlInfo); @@ -553,16 +572,17 @@ void InitGlobalAnimControls() anim_class_game_modes[anim_class_game_modes_list[i].class_bit] = anim_class_game_modes_list[i].game_mode; + anim_status_last_before_fading = GAME_MODE_LOADING; anim_status_last = GAME_MODE_LOADING; anim_classes_last = ANIM_CLASS_NONE; } -void InitGlobalAnimations() +void InitGlobalAnimations(void) { InitGlobalAnimControls(); } -void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage) +static void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage) { Bitmap *fade_bitmap = (drawing_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source : @@ -591,15 +611,23 @@ void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage) if (drawing_target == DRAW_TO_FADE_TARGET) after_fading = TRUE; + // special case: changing from/to this screen is done without fading + if (global.anim_status == GAME_MODE_PSEUDO_TYPENAME || + anim_status_last == GAME_MODE_PSEUDO_TYPENAME) + 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 - game_mode_anim_action[anim_status_last] = ANIM_STOP; + if (global.anim_status_next != anim_status_last_before_fading) + { + // stop animations for last screen before fading to new screen + game_mode_anim_action[anim_status_last] = ANIM_STOP; - // start animations for current screen - game_mode_anim_action[global.anim_status] = ANIM_START; + // start animations for current screen after fading to new screen + 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) @@ -628,7 +656,10 @@ void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage) if (drawing_target == DRAW_TO_SCREEN) { if (after_fading) + { anim_classes_last = anim_classes_next; + anim_status_last_before_fading = global.anim_status; + } anim_status_last = global.anim_status; @@ -784,7 +815,7 @@ void DrawGlobalAnimations(int drawing_target, int drawing_stage) ResetGlobalAnim_Clicked(); } -boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part) +static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part) { int viewport_x; int viewport_y; @@ -895,7 +926,10 @@ static void PlayGlobalAnimMusic(struct GlobalAnimPartControlInfo *part) if (!setup.sound_music) return; - PlayMusic(music); + if (IS_LOOP_MUSIC(music)) + PlayMusicLoop(music); + else + PlayMusic(music); #if 0 printf("::: PLAY MUSIC %d.%d.%d: %d\n", @@ -934,23 +968,65 @@ static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part) StopGlobalAnimMusic(part); } -static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask) +static void PlayGlobalAnimSoundIfLoop(struct GlobalAnimPartControlInfo *part) { - struct GraphicInfo *c = &part->control_info; - int trigger_mask = ANIM_EVENT_ANIM_MASK | ANIM_EVENT_PART_MASK; - int mask_anim_only = mask & ANIM_EVENT_ANIM_MASK; + // when drawing animations to fading buffer, do not play sounds + if (drawing_to_fading_buffer) + return; + + // loop sounds only expire when playing + if (game_status != GAME_MODE_PLAYING) + return; + + // check if any sound is defined for this animation part + if (part->sound == SND_UNDEFINED) + return; + + // normal (non-loop) sounds do not expire when playing + if (!IS_LOOP_SOUND(part->sound)) + return; + + // prevent expiring loop sounds when playing + PlayGlobalAnimSound(part); +} + +static boolean checkGlobalAnimEvent(int anim_event, int mask) +{ + int mask_anim_only = mask & ~ANIM_EVENT_PART_MASK; if (mask & ANIM_EVENT_ANY) - return (c->init_event & ANIM_EVENT_ANY || - c->anim_event & ANIM_EVENT_ANY); + return (anim_event & ANIM_EVENT_ANY); else if (mask & ANIM_EVENT_SELF) - return (c->init_event & ANIM_EVENT_SELF || - c->anim_event & ANIM_EVENT_SELF); + return (anim_event & ANIM_EVENT_SELF); else - return ((c->init_event & trigger_mask) == mask || - (c->anim_event & trigger_mask) == mask || - (c->init_event & trigger_mask) == mask_anim_only || - (c->anim_event & trigger_mask) == mask_anim_only); + return (anim_event == mask || + anim_event == mask_anim_only); +} + +static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask) +{ + struct GraphicInfo *c = &part->control_info; + int num_init_events = GetGlobalAnimEventValueCount(c->init_event); + int num_anim_events = GetGlobalAnimEventValueCount(c->anim_event); + int i; + + for (i = 0; i < num_init_events; i++) + { + int init_event = GetGlobalAnimEventValue(c->init_event, i); + + if (checkGlobalAnimEvent(init_event, mask)) + return TRUE; + } + + for (i = 0; i < num_anim_events; i++) + { + int anim_event = GetGlobalAnimEventValue(c->anim_event, i); + + if (checkGlobalAnimEvent(anim_event, mask)) + return TRUE; + } + + return FALSE; } static boolean isClickedPart(struct GlobalAnimPartControlInfo *part, @@ -983,7 +1059,13 @@ static boolean isClickedPart(struct GlobalAnimPartControlInfo *part, return TRUE; } -int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) +static boolean clickConsumed(struct GlobalAnimPartControlInfo *part) +{ + return (part->control_info.style & STYLE_PASSTHROUGH ? FALSE : TRUE); +} + +static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, + int state) { struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[part->mode_nr]; struct GlobalAnimMainControlInfo *anim = &ctrl->anim[part->anim_nr]; @@ -1009,8 +1091,8 @@ 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->init_event_state = (c->init_event != ANIM_EVENT_UNDEFINED); + part->anim_event_state = (c->anim_event != ANIM_EVENT_UNDEFINED); part->initial_anim_sync_frame = (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter); @@ -1097,27 +1179,27 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) part->step_yoffset = c->step_yoffset; if (part->init_delay_counter == 0 && - part->init_event_state == ANIM_EVENT_NONE) + !part->init_event_state) PlayGlobalAnimSoundAndMusic(part); } if (part->clicked && - part->init_event_state != ANIM_EVENT_NONE) + part->init_event_state) { 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->init_event_state = FALSE; part->clicked = FALSE; } if (part->clicked && - part->anim_event_state != ANIM_EVENT_NONE) + part->anim_event_state) { part->anim_delay_counter = 1; - part->anim_event_state = ANIM_EVENT_NONE; + part->anim_event_state = FALSE; part->clicked = FALSE; } @@ -1128,7 +1210,7 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) if (part->init_delay_counter == 0) { - part->init_event_state = ANIM_EVENT_NONE; + part->init_event_state = FALSE; PlayGlobalAnimSoundAndMusic(part); } @@ -1136,7 +1218,7 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) return ANIM_STATE_WAITING; } - if (part->init_event_state != ANIM_EVENT_NONE) + if (part->init_event_state) return ANIM_STATE_WAITING; // animation part is now running/visible and therefore clickable @@ -1149,7 +1231,7 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) (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; + part->anim_event_state = FALSE; // do not stop animation before "anim" or "post" counter are finished if (part->anim_delay_counter == 0 && @@ -1174,7 +1256,7 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) if (part->anim_delay_counter == 0) { - part->anim_event_state = ANIM_EVENT_NONE; + part->anim_event_state = FALSE; StopGlobalAnimSoundAndMusic(part); @@ -1199,6 +1281,9 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) return ANIM_STATE_WAITING; } + // special case to prevent expiring loop sounds when playing + PlayGlobalAnimSoundIfLoop(part); + if (!DelayReachedExt(&part->step_delay, part->step_delay_value, anim_sync_frame)) return ANIM_STATE_RUNNING; @@ -1224,11 +1309,14 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) return ANIM_STATE_RUNNING; } -void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) +static void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, + int action) { struct GlobalAnimPartControlInfo *part; struct GraphicInfo *c = &anim->control_info; + int num_parts = anim->num_parts + (anim->has_base ? 1 : 0); int state, active_part_nr; + int i; #if 0 printf("::: HandleGlobalAnim_Main: %d, %d => %d\n", @@ -1269,13 +1357,8 @@ void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) case ANIM_STOP: anim->state = ANIM_STATE_INACTIVE; - { - int num_parts = anim->num_parts + (anim->has_base ? 1 : 0); - int i; - - for (i = 0; i < num_parts; i++) - StopGlobalAnimSoundAndMusic(&anim->part[i]); - } + for (i = 0; i < num_parts; i++) + StopGlobalAnimSoundAndMusic(&anim->part[i]); return; @@ -1285,9 +1368,6 @@ void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) 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); @@ -1339,6 +1419,11 @@ void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) part = &anim->part[anim->active_part_nr]; + // first set all animation parts to "inactive", ... + for (i = 0; i < num_parts; i++) + anim->part[i].state = ANIM_STATE_INACTIVE; + + // ... then set current animation parts to "running" part->state = ANIM_STATE_RUNNING; anim->state = HandleGlobalAnim_Part(part, anim->state); @@ -1377,7 +1462,7 @@ void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) anim->last_active_part_nr = active_part_nr; } -void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action) +static void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action) { int i; @@ -1399,7 +1484,7 @@ static void HandleGlobalAnim(int action, int game_mode) HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action); } -static void DoAnimationExt() +static void DoAnimationExt(void) { int i; @@ -1419,7 +1504,25 @@ static void DoAnimationExt() #endif } -static void InitGlobalAnim_Clickable() +static boolean DoGlobalAnim_EventAction(struct GlobalAnimPartControlInfo *part) +{ + int anim_event_action = part->control_info.anim_event_action; + + if (anim_event_action == -1) + return FALSE; + + boolean action_executed = (DoGadgetAction(anim_event_action) || + DoScreenAction(anim_event_action) || + DoKeysymAction(anim_event_action)); + + // check if further actions are allowed to be executed + if (part->control_info.style & STYLE_MULTIPLE_ACTIONS) + return FALSE; + + return action_executed; +} + +static void InitGlobalAnim_Clickable(void) { int mode_nr; @@ -1445,20 +1548,25 @@ static void InitGlobalAnim_Clickable() static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked) { + boolean anything_clicked = FALSE; boolean any_part_clicked = FALSE; + boolean any_event_action = FALSE; int mode_nr; - for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++) + // check game modes in reverse draw order (to stop when clicked) + for (mode_nr = NUM_GAME_MODES - 1; mode_nr >= 0; mode_nr--) { struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr]; int anim_nr; - for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++) + // check animations in reverse draw order (to stop when clicked) + for (anim_nr = ctrl->num_anims - 1; anim_nr >= 0; anim_nr--) { struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr]; int part_nr; - for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++) + // check animation parts in reverse draw order (to stop when clicked) + for (part_nr = anim->num_parts_all - 1; part_nr >= 0; part_nr--) { struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; @@ -1472,22 +1580,44 @@ static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked) if (!part->clickable) continue; + if (part->state != ANIM_STATE_RUNNING) + continue; + + // always handle "any" click events (clicking anywhere on screen) ... if (isClickablePart(part, ANIM_EVENT_ANY)) - any_part_clicked = part->clicked = TRUE; + { + part->clicked = TRUE; + anything_clicked = clickConsumed(part); + } + + // ... but only handle the first (topmost) clickable animation + if (any_part_clicked) + continue; if (isClickedPart(part, mx, my, clicked)) { #if 0 - printf("::: %d.%d CLICKED\n", anim_nr, part_nr); + printf("::: %d.%d CLICKED [%d]\n", anim_nr, part_nr, + part->control_info.anim_event_action); #endif + // after executing event action, ignore any further actions + if (!any_event_action && DoGlobalAnim_EventAction(part)) + any_event_action = TRUE; + + // determine if mouse clicks should be blocked from other animations + any_part_clicked = clickConsumed(part); + if (isClickablePart(part, ANIM_EVENT_SELF)) - any_part_clicked = part->clicked = TRUE; + { + part->clicked = TRUE; + anything_clicked = clickConsumed(part); + } // check if this click is defined to trigger other animations int gic_anim_nr = part->old_anim_nr + 1; // X as in "anim_X" int gic_part_nr = part->old_nr + 1; // Y as in "part_Y" - int mask = gic_anim_nr << ANIM_EVENT_ANIM_BIT; + int mask = ANIM_EVENT_CLICK | (gic_anim_nr << ANIM_EVENT_ANIM_BIT); if (!part->is_base) mask |= gic_part_nr << ANIM_EVENT_PART_BIT; @@ -1503,8 +1633,23 @@ static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked) { struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr]; + if (part2->state != ANIM_STATE_RUNNING) + continue; + if (isClickablePart(part2, mask)) - any_part_clicked = part2->clicked = TRUE; + { + part2->clicked = TRUE; + anything_clicked = clickConsumed(part); // click was on "part"! + +#if 0 + printf("::: %d.%d TRIGGER CLICKED [%d]\n", anim2_nr, part2_nr, + part2->control_info.anim_event_action); +#endif + + // after executing event action, ignore any further actions + if (!any_event_action && DoGlobalAnim_EventAction(part2)) + any_event_action = TRUE; + } #if 0 struct GraphicInfo *c = &part2->control_info; @@ -1525,15 +1670,15 @@ static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked) } } - return any_part_clicked; + return (anything_clicked || any_event_action); } -static void ResetGlobalAnim_Clickable() +static void ResetGlobalAnim_Clickable(void) { InitGlobalAnim_Clickable(); } -static void ResetGlobalAnim_Clicked() +static void ResetGlobalAnim_Clicked(void) { InitGlobalAnim_Clicked(-1, -1, FALSE); } @@ -1546,7 +1691,7 @@ boolean HandleGlobalAnimClicks(int mx, int my, int button) boolean release_event; boolean click_consumed_current = click_consumed; - /* check if button state has changed since last invocation */ + // 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;