X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fcartoons.c;h=2e74c72b92a5683da4063eb88a88ff1fd6381775;hp=0352e4f85ab17ed5fa8babc68a3c8798d8dce6ab;hb=3466bff66861926f480a96e5b8923a4e044d50a4;hpb=9f88e49643566b03fbd6e92509bb66fd42bc1daa diff --git a/src/cartoons.c b/src/cartoons.c index 0352e4f8..2e74c72b 100644 --- a/src/cartoons.c +++ b/src/cartoons.c @@ -24,17 +24,30 @@ #define NUM_GLOBAL_ANIM_PARTS_AND_TOONS MAX(NUM_GLOBAL_ANIM_PARTS_ALL, \ NUM_GLOBAL_TOON_PARTS) -#define ANIM_CLASS_BIT_SUBMENU 0 -#define ANIM_CLASS_BIT_MENU 1 -#define ANIM_CLASS_BIT_TOONS 2 +#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 NUM_ANIM_CLASSES 3 +#define NUM_ANIM_CLASSES 6 #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_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_TOONS_MENU_MAIN (ANIM_CLASS_TOONS | \ + ANIM_CLASS_MENU | \ + ANIM_CLASS_MAIN) + +#define ANIM_CLASS_TOONS_MENU_SUBMENU (ANIM_CLASS_TOONS | \ + ANIM_CLASS_MENU | \ + ANIM_CLASS_SUBMENU) struct GlobalAnimPartControlInfo { @@ -42,7 +55,9 @@ struct GlobalAnimPartControlInfo int anim_nr; int mode_nr; + int sound; int graphic; + struct GraphicInfo graphic_info; struct GraphicInfo control_info; @@ -86,6 +101,8 @@ struct GlobalAnimMainControlInfo int init_delay_counter; int state; + + int last_state, last_active_part_nr; }; struct GlobalAnimControlInfo @@ -102,14 +119,25 @@ struct GameModeAnimClass int class; } game_mode_anim_classes_list[] = { - { GAME_MODE_LEVELS, ANIM_CLASS_TOONS | ANIM_CLASS_MENU | ANIM_CLASS_SUBMENU }, - { GAME_MODE_LEVELNR,ANIM_CLASS_TOONS | ANIM_CLASS_MENU | ANIM_CLASS_SUBMENU }, - { GAME_MODE_INFO, ANIM_CLASS_TOONS | ANIM_CLASS_MENU | ANIM_CLASS_SUBMENU }, - { GAME_MODE_SETUP, ANIM_CLASS_TOONS | ANIM_CLASS_MENU | ANIM_CLASS_SUBMENU }, - { GAME_MODE_MAIN, ANIM_CLASS_TOONS | ANIM_CLASS_MENU }, - { GAME_MODE_SCORES, ANIM_CLASS_TOONS }, - - { -1, -1 } + { GAME_MODE_TITLE_INITIAL_1, ANIM_CLASS_TITLE_INITIAL }, + { GAME_MODE_TITLE_INITIAL_2, ANIM_CLASS_TITLE_INITIAL }, + { GAME_MODE_TITLE_INITIAL_3, ANIM_CLASS_TITLE_INITIAL }, + { GAME_MODE_TITLE_INITIAL_4, ANIM_CLASS_TITLE_INITIAL }, + { GAME_MODE_TITLE_INITIAL_5, ANIM_CLASS_TITLE_INITIAL }, + { GAME_MODE_TITLE_1, ANIM_CLASS_TITLE }, + { GAME_MODE_TITLE_2, ANIM_CLASS_TITLE }, + { GAME_MODE_TITLE_3, ANIM_CLASS_TITLE }, + { GAME_MODE_TITLE_4, ANIM_CLASS_TITLE }, + { GAME_MODE_TITLE_5, ANIM_CLASS_TITLE }, + { GAME_MODE_LEVELS, ANIM_CLASS_TOONS_MENU_SUBMENU }, + { GAME_MODE_LEVELNR, ANIM_CLASS_TOONS_MENU_SUBMENU }, + { GAME_MODE_INFO, ANIM_CLASS_TOONS_MENU_SUBMENU }, + { 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 }, + + { -1, -1 } }; struct AnimClassGameMode @@ -118,11 +146,14 @@ struct AnimClassGameMode int game_mode; } anim_class_game_modes_list[] = { - { ANIM_CLASS_BIT_SUBMENU, GAME_MODE_PSEUDO_SUBMENU }, - { ANIM_CLASS_BIT_MENU, GAME_MODE_PSEUDO_MENU }, - { ANIM_CLASS_BIT_TOONS, GAME_MODE_PSEUDO_TOONS }, - - { -1, -1 } + { 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_SUBMENU, GAME_MODE_PSEUDO_SUBMENU }, + { ANIM_CLASS_BIT_MENU, GAME_MODE_PSEUDO_MENU }, + { ANIM_CLASS_BIT_TOONS, GAME_MODE_PSEUDO_TOONS }, + + { -1, -1 } }; /* forward declaration for internal use */ @@ -160,6 +191,38 @@ static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim) return part_nr; } +static int compareGlobalAnimPartControlInfo(const void *obj1, const void *obj2) +{ + const struct GlobalAnimPartControlInfo *o1 = + (struct GlobalAnimPartControlInfo *)obj1; + const struct GlobalAnimPartControlInfo *o2 = + (struct GlobalAnimPartControlInfo *)obj2; + int compare_result; + + if (o1->control_info.draw_order != o2->control_info.draw_order) + compare_result = o1->control_info.draw_order - o2->control_info.draw_order; + else + compare_result = o1->nr - o2->nr; + + return compare_result; +} + +static int compareGlobalAnimMainControlInfo(const void *obj1, const void *obj2) +{ + const struct GlobalAnimMainControlInfo *o1 = + (struct GlobalAnimMainControlInfo *)obj1; + const struct GlobalAnimMainControlInfo *o2 = + (struct GlobalAnimMainControlInfo *)obj2; + int compare_result; + + if (o1->control_info.draw_order != o2->control_info.draw_order) + compare_result = o1->control_info.draw_order - o2->control_info.draw_order; + else + compare_result = o1->nr - o2->nr; + + return compare_result; +} + static void PrepareBackbuffer() { if (game_status != GAME_MODE_PLAYING) @@ -248,12 +311,14 @@ static void InitToonControls() for (i = 0; i < num_toons; i++) { struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; + int sound = SND_UNDEFINED; int graphic = IMG_TOON_1 + i; int control = graphic; part->nr = part_nr; part->anim_nr = anim_nr; part->mode_nr = mode_nr; + part->sound = sound; part->graphic = graphic; part->graphic_info = graphic_info[graphic]; part->control_info = graphic_info[control]; @@ -285,7 +350,7 @@ void InitGlobalAnimControls() { int i, m, a, p; int mode_nr, anim_nr, part_nr; - int graphic, control; + int sound, graphic, control; anim_sync_frame = 0; @@ -333,6 +398,7 @@ void InitGlobalAnimControls() { struct GlobalAnimPartControlInfo *part = &anim->part[part_nr]; + sound = global_anim_info[a].sound[p][m]; graphic = global_anim_info[a].graphic[p][m]; control = global_anim_info[ctrl_id].graphic[p][m]; @@ -345,9 +411,15 @@ void InitGlobalAnimControls() m, a, p, mode_nr, anim_nr, part_nr, control); #endif +#if 0 + printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n", + m, a, p, mode_nr, anim_nr, part_nr, sound); +#endif + part->nr = part_nr; part->anim_nr = anim_nr; part->mode_nr = mode_nr; + part->sound = sound; part->graphic = graphic; part->graphic_info = graphic_info[graphic]; part->control_info = graphic_info[control]; @@ -382,6 +454,27 @@ void InitGlobalAnimControls() InitToonControls(); + /* 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 */ + qsort(ctrl->anim, ctrl->num_anims, + sizeof(struct GlobalAnimMainControlInfo), + compareGlobalAnimMainControlInfo); + + for (a = 0; a < ctrl->num_anims; a++) + { + struct GlobalAnimMainControlInfo *anim = &ctrl->anim[a]; + + /* sort all animation parts for this main animation */ + qsort(anim->part, anim->num_parts, + sizeof(struct GlobalAnimPartControlInfo), + compareGlobalAnimPartControlInfo); + } + } + for (i = 0; i < NUM_GAME_MODES; i++) game_mode_anim_classes[i] = ANIM_CLASS_NONE; for (i = 0; game_mode_anim_classes_list[i].game_mode != -1; i++) @@ -405,14 +498,19 @@ void InitGlobalAnimations() void DrawGlobalAnimExt(int drawing_stage) { - int anim_classes = game_mode_anim_classes[global.anim_status_next]; int mode_nr; - int i; - // start or stop global animations by change of game mode - // (special handling of animations for "current screen" and "all screens") if (global.anim_status != anim_status_last) { + boolean before_fading = (global.anim_status == GAME_MODE_PSEUDO_FADING); + boolean after_fading = (anim_status_last == GAME_MODE_PSEUDO_FADING); + int anim_classes_next = game_mode_anim_classes[global.anim_status_next]; + int i; + + // ---------- 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); @@ -423,27 +521,30 @@ void DrawGlobalAnimExt(int drawing_stage) if (anim_status_last == GAME_MODE_LOADING) HandleGlobalAnim(ANIM_START, GAME_MODE_DEFAULT); - anim_status_last = global.anim_status; - } + // ---------- part 2 ------------------------------------------------------ + // start or stop global animations by change of animation class + // (generic handling of animations for "class of screens") - // start or stop global animations by change of animation class - // (generic handling of animations for "class of screens") - if (anim_classes != anim_classes_last) - { for (i = 0; i < NUM_ANIM_CLASSES; i++) { int anim_class_check = (1 << i); int anim_class_game_mode = anim_class_game_modes[i]; int anim_class_last = anim_classes_last & anim_class_check; - int anim_class = anim_classes & anim_class_check; + int anim_class_next = anim_classes_next & anim_class_check; - if (anim_class_last && !anim_class) + // 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); - else if (!anim_class_last && anim_class) + + // 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); } - anim_classes_last = anim_classes; + if (after_fading) + anim_classes_last = anim_classes_next; + + anim_status_last = global.anim_status; } if (!setup.toons || global.anim_status == GAME_MODE_LOADING) @@ -522,6 +623,9 @@ void DrawGlobalAnimExt(int drawing_stage) else if (part->y > part->viewport_height - g->height) height -= (part->y - (part->viewport_height - g->height)); + if (width <= 0 || height <= 0) + continue; + dst_x += part->viewport_x; dst_y += part->viewport_y; @@ -611,6 +715,44 @@ boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part) return changed; } +void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part) +{ + int sound = part->sound; + + if (sound == SND_UNDEFINED) + return; + + if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) || + (!setup.sound_loops && IS_LOOP_SOUND(sound))) + return; + + // !!! TODO: ADD STEREO POSITION FOR MOVING ANIMATIONS !!! + if (IS_LOOP_SOUND(sound)) + PlaySoundLoop(sound); + else + PlaySound(sound); + +#if 0 + printf("::: PLAY %d.%d.%d: %d\n", + part->anim_nr, part->nr, part->mode_nr, sound); +#endif +} + +void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part) +{ + int sound = part->sound; + + if (sound == SND_UNDEFINED) + return; + + StopSound(sound); + +#if 0 + printf("::: STOP %d.%d.%d: %d\n", + part->anim_nr, part->nr, part->mode_nr, sound); +#endif +} + int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) { struct GraphicInfo *g = &part->graphic_info; @@ -705,20 +847,43 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) 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) + PlayGlobalAnimSound(part); } if (part->init_delay_counter > 0) { part->init_delay_counter--; + if (part->init_delay_counter == 0) + PlayGlobalAnimSound(part); + 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)) - return ANIM_STATE_RESTART; + { + // do not stop animation before "anim" or "post" counter are finished + if (part->anim_delay_counter == 0 && + part->post_delay_counter == 0) + { + StopGlobalAnimSound(part); + + part->post_delay_counter = + (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random)); + + if (part->post_delay_counter > 0) + return ANIM_STATE_RUNNING; + + // drawing last frame not needed here -- animation not visible anymore + return ANIM_STATE_RESTART; + } + } if (part->anim_delay_counter > 0) { @@ -726,12 +891,15 @@ int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state) if (part->anim_delay_counter == 0) { + StopGlobalAnimSound(part); + part->post_delay_counter = (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random)); if (part->post_delay_counter > 0) return ANIM_STATE_RUNNING; + // additional state "RUNNING" required to not skip drawing last frame return ANIM_STATE_RESTART | ANIM_STATE_RUNNING; } } @@ -772,7 +940,7 @@ void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) { struct GlobalAnimPartControlInfo *part; struct GraphicInfo *c = &anim->control_info; - boolean skip = FALSE; + int state, active_part_nr; #if 0 printf("::: HandleGlobalAnim_Main: %d, %d => %d\n", @@ -795,24 +963,33 @@ void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) switch (action) { case ANIM_START: - anim->state = ANIM_STATE_RESTART; + anim->state = anim->last_state = ANIM_STATE_RESTART; + anim->active_part_nr = anim->last_active_part_nr = 0; anim->part_counter = 0; - anim->active_part_nr = 0; - skip = TRUE; break; case ANIM_CONTINUE: if (anim->state == ANIM_STATE_INACTIVE) - skip = TRUE; + return; + + anim->state = anim->last_state; + anim->active_part_nr = anim->last_active_part_nr; break; case ANIM_STOP: anim->state = ANIM_STATE_INACTIVE; - skip = TRUE; - break; + { + int num_parts = anim->num_parts + (anim->has_base ? 1 : 0); + int i; + + for (i = 0; i < num_parts; i++) + StopGlobalAnimSound(&anim->part[i]); + } + + return; default: break; @@ -837,37 +1014,37 @@ void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) case ANIM_START: anim->state = ANIM_STATE_RUNNING; part->state = ANIM_STATE_RESTART; - skip = TRUE; break; case ANIM_CONTINUE: if (part->state == ANIM_STATE_INACTIVE) - skip = TRUE; + continue; break; case ANIM_STOP: part->state = ANIM_STATE_INACTIVE; - skip = TRUE; - break; + continue; default: break; } - if (skip) - continue; - 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; - } + anim->last_state = anim->state; + anim->last_active_part_nr = anim->active_part_nr; - if (skip) return; + } if (anim->state & ANIM_STATE_RESTART) // directly after restart anim->active_part_nr = getGlobalAnimationPart(anim); @@ -880,6 +1057,36 @@ void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action) 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; + + state = anim->state; + active_part_nr = anim->active_part_nr; + + // while the animation parts are pausing (waiting or inactive), play the base + // (main) animation; this corresponds to the "boring player animation" logic + // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!) + if (anim->has_base) + { + if (anim->state == ANIM_STATE_WAITING || + anim->state == ANIM_STATE_INACTIVE) + { + anim->active_part_nr = anim->num_parts; // part nr of base animation + part = &anim->part[anim->active_part_nr]; + + if (anim->state != anim->last_state) + part->state = ANIM_STATE_RESTART; + + anim->state = ANIM_STATE_RUNNING; + part->state = HandleGlobalAnim_Part(part, part->state); + } + } + + anim->last_state = state; + anim->last_active_part_nr = active_part_nr; } void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)