X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fanim.c;h=48393eb3141f320c38f1f58fe9c88afd7676a651;hp=50cbba7b73521e650248525867e655b447f16e7e;hb=897c46a2720672a49ce6d0803b08eed23fd2dd90;hpb=ee8086c220663ad470ed61b1cef90eeb66be5cb1 diff --git a/src/anim.c b/src/anim.c index 50cbba7b..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, \ @@ -33,8 +36,9 @@ #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 7 +#define NUM_ANIM_CLASSES 8 #define ANIM_CLASS_NONE 0 #define ANIM_CLASS_TITLE_INITIAL (1 << ANIM_CLASS_BIT_TITLE_INITIAL) @@ -44,25 +48,29 @@ #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_SCORES (ANIM_CLASS_TOONS | \ - ANIM_CLASS_SCORES) +#define ANIM_CLASS_TOONS_SCORES (ANIM_CLASS_TOONS | \ + ANIM_CLASS_SCORES | \ + ANIM_CLASS_NO_TITLE) -#define ANIM_CLASS_TOONS_MENU_MAIN (ANIM_CLASS_TOONS | \ - ANIM_CLASS_MENU | \ - ANIM_CLASS_MAIN) +#define ANIM_CLASS_TOONS_MENU_MAIN (ANIM_CLASS_TOONS | \ + ANIM_CLASS_MENU | \ + ANIM_CLASS_MAIN | \ + ANIM_CLASS_NO_TITLE) -#define ANIM_CLASS_TOONS_MENU_SUBMENU (ANIM_CLASS_TOONS | \ - ANIM_CLASS_MENU | \ - ANIM_CLASS_SUBMENU) +#define ANIM_CLASS_TOONS_MENU_SUBMENU (ANIM_CLASS_TOONS | \ + ANIM_CLASS_MENU | \ + ANIM_CLASS_SUBMENU | \ + ANIM_CLASS_NO_TITLE) -/* values for global animation states */ +// 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 @@ -172,6 +180,8 @@ struct GameModeAnimClass { GAME_MODE_PSEUDO_TYPENAME, ANIM_CLASS_TOONS_MENU_MAIN }, { 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 } }; @@ -189,15 +199,16 @@ struct AnimClassGameMode { 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]; @@ -213,9 +224,9 @@ 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) @@ -224,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); @@ -263,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) { @@ -323,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]; @@ -405,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; @@ -528,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); @@ -542,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); @@ -566,12 +577,12 @@ void InitGlobalAnimControls() 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 : @@ -804,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; @@ -915,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", @@ -954,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, @@ -1008,7 +1064,8 @@ static boolean clickConsumed(struct GlobalAnimPartControlInfo *part) return (part->control_info.style & STYLE_PASSTHROUGH ? FALSE : TRUE); } -int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) +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]; @@ -1034,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); @@ -1122,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; } @@ -1153,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); } @@ -1161,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 @@ -1174,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 && @@ -1199,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); @@ -1224,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; @@ -1249,7 +1309,8 @@ 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; @@ -1401,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; @@ -1423,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; @@ -1450,11 +1511,18 @@ static boolean DoGlobalAnim_EventAction(struct GlobalAnimPartControlInfo *part) if (anim_event_action == -1) return FALSE; - return (DoGadgetAction(anim_event_action) || - DoScreenAction(anim_event_action)); + 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() +static void InitGlobalAnim_Clickable(void) { int mode_nr; @@ -1537,7 +1605,8 @@ static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked) if (!any_event_action && DoGlobalAnim_EventAction(part)) any_event_action = TRUE; - any_part_clicked = TRUE; + // determine if mouse clicks should be blocked from other animations + any_part_clicked = clickConsumed(part); if (isClickablePart(part, ANIM_EVENT_SELF)) { @@ -1548,7 +1617,7 @@ static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked) // 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; @@ -1604,12 +1673,12 @@ static boolean InitGlobalAnim_Clicked(int mx, int my, boolean 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); } @@ -1622,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;