From: Holger Schemel Date: Sat, 30 Aug 2014 08:53:10 +0000 (+0200) Subject: Merge branch 'master' into releases X-Git-Tag: 3.2.2 X-Git-Url: https://git.artsoft.org/?a=commitdiff_plain;h=refs%2Ftags%2F3.2.2;hp=0bb8665ef2b5ff5430dd6808b0be7761912ce4e2;p=rocksndiamonds.git Merge branch 'master' into releases --- diff --git a/ChangeLog b/ChangeLog index da91536c..960d5063 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-08-29 + * fixed bug with redrawing screen in fullscreen mode after quick tape + reloading when using the EMC game engine + +2006-08-28 + * fixed bug in GameWon() when level contains no exit (like in Sokoban) + +2006-08-23 + * added engine snapshot functionality for instant tape reloading (this + only works for the last tape saved using "quick save", and does not + work across program restarts, because it completely works in memory) + +2006-08-21 + * version number set to 3.2.2 + 2006-08-20 * version 3.2.1 released @@ -50,7 +65,7 @@ (useful if default mode 800 x 600 does not match screen aspect ratio) 2006-07-30 - * improved down-scaling of images for better level and preview graphics + * improved down-scaling of images for better editor and preview graphics * changed user data directory for Mac OS X from Unix style to new place 2006-07-26 diff --git a/src/conf_e2g.c b/src/conf_e2g.c index d597d1b3..5f1685b4 100644 --- a/src/conf_e2g.c +++ b/src/conf_e2g.c @@ -2830,36 +2830,36 @@ element_to_graphic[] = IMG_CURRENT_CE_SCORE }, { - EL_LAST_CE_1, -1, -1, FALSE, - IMG_LAST_CE_1 + EL_PREV_CE_1, -1, -1, FALSE, + IMG_PREV_CE_1 }, { - EL_LAST_CE_2, -1, -1, FALSE, - IMG_LAST_CE_2 + EL_PREV_CE_2, -1, -1, FALSE, + IMG_PREV_CE_2 }, { - EL_LAST_CE_3, -1, -1, FALSE, - IMG_LAST_CE_3 + EL_PREV_CE_3, -1, -1, FALSE, + IMG_PREV_CE_3 }, { - EL_LAST_CE_4, -1, -1, FALSE, - IMG_LAST_CE_4 + EL_PREV_CE_4, -1, -1, FALSE, + IMG_PREV_CE_4 }, { - EL_LAST_CE_5, -1, -1, FALSE, - IMG_LAST_CE_5 + EL_PREV_CE_5, -1, -1, FALSE, + IMG_PREV_CE_5 }, { - EL_LAST_CE_6, -1, -1, FALSE, - IMG_LAST_CE_6 + EL_PREV_CE_6, -1, -1, FALSE, + IMG_PREV_CE_6 }, { - EL_LAST_CE_7, -1, -1, FALSE, - IMG_LAST_CE_7 + EL_PREV_CE_7, -1, -1, FALSE, + IMG_PREV_CE_7 }, { - EL_LAST_CE_8, -1, -1, FALSE, - IMG_LAST_CE_8 + EL_PREV_CE_8, -1, -1, FALSE, + IMG_PREV_CE_8 }, { EL_NEXT_CE_1, -1, -1, FALSE, diff --git a/src/conf_gfx.c b/src/conf_gfx.c index 3596063d..b67f1f53 100644 --- a/src/conf_gfx.c +++ b/src/conf_gfx.c @@ -3484,45 +3484,45 @@ struct ConfigInfo image_config[] = { "current_ce_score.ypos", "12" }, { "current_ce_score.frames", "1" }, - { "last_ce_1", "RocksMore.pcx" }, - { "last_ce_1.xpos", "0" }, - { "last_ce_1.ypos", "7" }, - { "last_ce_1.frames", "1" }, - - { "last_ce_2", "RocksMore.pcx" }, - { "last_ce_2.xpos", "1" }, - { "last_ce_2.ypos", "7" }, - { "last_ce_2.frames", "1" }, - - { "last_ce_3", "RocksMore.pcx" }, - { "last_ce_3.xpos", "2" }, - { "last_ce_3.ypos", "7" }, - { "last_ce_3.frames", "1" }, - - { "last_ce_4", "RocksMore.pcx" }, - { "last_ce_4.xpos", "3" }, - { "last_ce_4.ypos", "7" }, - { "last_ce_4.frames", "1" }, - - { "last_ce_5", "RocksMore.pcx" }, - { "last_ce_5.xpos", "4" }, - { "last_ce_5.ypos", "7" }, - { "last_ce_5.frames", "1" }, - - { "last_ce_6", "RocksMore.pcx" }, - { "last_ce_6.xpos", "5" }, - { "last_ce_6.ypos", "7" }, - { "last_ce_6.frames", "1" }, - - { "last_ce_7", "RocksMore.pcx" }, - { "last_ce_7.xpos", "6" }, - { "last_ce_7.ypos", "7" }, - { "last_ce_7.frames", "1" }, - - { "last_ce_8", "RocksMore.pcx" }, - { "last_ce_8.xpos", "7" }, - { "last_ce_8.ypos", "7" }, - { "last_ce_8.frames", "1" }, + { "prev_ce_1", "RocksMore.pcx" }, + { "prev_ce_1.xpos", "0" }, + { "prev_ce_1.ypos", "7" }, + { "prev_ce_1.frames", "1" }, + + { "prev_ce_2", "RocksMore.pcx" }, + { "prev_ce_2.xpos", "1" }, + { "prev_ce_2.ypos", "7" }, + { "prev_ce_2.frames", "1" }, + + { "prev_ce_3", "RocksMore.pcx" }, + { "prev_ce_3.xpos", "2" }, + { "prev_ce_3.ypos", "7" }, + { "prev_ce_3.frames", "1" }, + + { "prev_ce_4", "RocksMore.pcx" }, + { "prev_ce_4.xpos", "3" }, + { "prev_ce_4.ypos", "7" }, + { "prev_ce_4.frames", "1" }, + + { "prev_ce_5", "RocksMore.pcx" }, + { "prev_ce_5.xpos", "4" }, + { "prev_ce_5.ypos", "7" }, + { "prev_ce_5.frames", "1" }, + + { "prev_ce_6", "RocksMore.pcx" }, + { "prev_ce_6.xpos", "5" }, + { "prev_ce_6.ypos", "7" }, + { "prev_ce_6.frames", "1" }, + + { "prev_ce_7", "RocksMore.pcx" }, + { "prev_ce_7.xpos", "6" }, + { "prev_ce_7.ypos", "7" }, + { "prev_ce_7.frames", "1" }, + + { "prev_ce_8", "RocksMore.pcx" }, + { "prev_ce_8.xpos", "7" }, + { "prev_ce_8.ypos", "7" }, + { "prev_ce_8.frames", "1" }, { "next_ce_1", "RocksMore.pcx" }, { "next_ce_1.xpos", "0" }, diff --git a/src/conf_gfx.h b/src/conf_gfx.h index 06f4ffe6..332c6ac0 100644 --- a/src/conf_gfx.h +++ b/src/conf_gfx.h @@ -724,14 +724,14 @@ #define IMG_TRIGGER_CE_SCORE 703 #define IMG_CURRENT_CE_VALUE 704 #define IMG_CURRENT_CE_SCORE 705 -#define IMG_LAST_CE_1 706 -#define IMG_LAST_CE_2 707 -#define IMG_LAST_CE_3 708 -#define IMG_LAST_CE_4 709 -#define IMG_LAST_CE_5 710 -#define IMG_LAST_CE_6 711 -#define IMG_LAST_CE_7 712 -#define IMG_LAST_CE_8 713 +#define IMG_PREV_CE_1 706 +#define IMG_PREV_CE_2 707 +#define IMG_PREV_CE_3 708 +#define IMG_PREV_CE_4 709 +#define IMG_PREV_CE_5 710 +#define IMG_PREV_CE_6 711 +#define IMG_PREV_CE_7 712 +#define IMG_PREV_CE_8 713 #define IMG_NEXT_CE_1 714 #define IMG_NEXT_CE_2 715 #define IMG_NEXT_CE_3 716 diff --git a/src/conftime.h b/src/conftime.h index 0fba9bbe..78c8fc41 100644 --- a/src/conftime.h +++ b/src/conftime.h @@ -1 +1 @@ -#define COMPILE_DATE_STRING "[2006-08-20 20:05]" +#define COMPILE_DATE_STRING "[2006-08-29 23:29]" diff --git a/src/editor.c b/src/editor.c index 6ec3cd8f..2a7a8e4e 100644 --- a/src/editor.c +++ b/src/editor.c @@ -4144,15 +4144,15 @@ static int editor_el_reference[] = EL_CURRENT_CE_VALUE, EL_CURRENT_CE_SCORE, - EL_LAST_CE_8, - EL_LAST_CE_7, - EL_LAST_CE_6, - EL_LAST_CE_5, - - EL_LAST_CE_4, - EL_LAST_CE_3, - EL_LAST_CE_2, - EL_LAST_CE_1, + EL_PREV_CE_8, + EL_PREV_CE_7, + EL_PREV_CE_6, + EL_PREV_CE_5, + + EL_PREV_CE_4, + EL_PREV_CE_3, + EL_PREV_CE_2, + EL_PREV_CE_1, EL_NEXT_CE_1, EL_NEXT_CE_2, diff --git a/src/events.c b/src/events.c index d42acf56..65b06803 100644 --- a/src/events.c +++ b/src/events.c @@ -245,7 +245,11 @@ void ClearEventQueue() break; case EVENT_KEYRELEASE: +#if 1 + ClearPlayerAction(); +#else key_joystick_mapping = 0; +#endif break; default: @@ -700,8 +704,14 @@ void HandleKey(Key key, int key_status) return; } +#if 1 + if (game_status == GAME_MODE_PLAYING && + local_player->LevelSolved_GameEnd && + (key == KSYM_Return || key == setup.shortcut.toggle_pause)) +#else if (game_status == GAME_MODE_PLAYING && AllPlayersGone && (key == KSYM_Return || key == setup.shortcut.toggle_pause)) +#endif { GameEnd(); @@ -1045,7 +1055,11 @@ void HandleJoystick() if (tape.playing || keyboard) newbutton = ((joy & JOY_BUTTON) != 0); +#if 1 + if (local_player->LevelSolved_GameEnd && newbutton) +#else if (AllPlayersGone && newbutton) +#endif { GameEnd(); diff --git a/src/game.c b/src/game.c index fea0d6ce..d8eb7353 100644 --- a/src/game.c +++ b/src/game.c @@ -142,7 +142,7 @@ #define GET_DX_FROM_DIR(d) ((d) == MV_LEFT ? -1 : (d) == MV_RIGHT ? 1 : 0) #define GET_DY_FROM_DIR(d) ((d) == MV_UP ? -1 : (d) == MV_DOWN ? 1 : 0) -#define INIT_GFX_RANDOM() (SimpleRND(1000000)) +#define INIT_GFX_RANDOM() (GetSimpleRandom(1000000)) #define GET_NEW_PUSH_DELAY(e) ( (element_info[e].push_delay_fixed) + \ RND(element_info[e].push_delay_random)) @@ -176,7 +176,7 @@ (e) == EL_TRIGGER_CE_SCORE ? (ch)->actual_trigger_ce_score : \ (e) == EL_CURRENT_CE_VALUE ? (cv) : \ (e) == EL_CURRENT_CE_SCORE ? (cs) : \ - (e) >= EL_LAST_CE_8 && (e) <= EL_NEXT_CE_8 ? \ + (e) >= EL_PREV_CE_8 && (e) <= EL_NEXT_CE_8 ? \ RESOLVED_REFERENCE_ELEMENT(be, e) : \ (e)) @@ -2671,12 +2671,14 @@ void GameWon() static int game_over_delay = 0; int game_over_delay_value = 50; - /* do not start end game actions before the player stops moving (to exit) */ - if (local_player->MovPos) - return; - if (!local_player->LevelSolved_GameEnd) { + int i; + + /* do not start end game actions before the player stops moving (to exit) */ + if (local_player->MovPos) + return; + local_player->LevelSolved_GameEnd = TRUE; local_player->LevelSolved_SaveTape = tape.recording; local_player->LevelSolved_SaveScore = !tape.playing; @@ -2684,6 +2686,10 @@ void GameWon() if (tape.auto_play) /* tape might already be stopped here */ tape.auto_play_level_solved = TRUE; +#if 1 + TapeStop(); +#endif + game_over_delay = game_over_delay_value; time = time_final = (level.time == 0 ? TimePlayed : TimeLeft); @@ -2730,6 +2736,19 @@ void GameWon() DrawLevelField(ExitX, ExitY); } + for (i = 0; i < MAX_PLAYERS; i++) + { + struct PlayerInfo *player = &stored_player[i]; + + if (player->present) + { + RemovePlayer(player); + + /* player disappears */ + DrawLevelField(player->jx, player->jy); + } + } + PlaySound(SND_GAME_WINNING); } @@ -2770,7 +2789,9 @@ void GameEnd() if (local_player->LevelSolved_SaveTape) { +#if 0 TapeStop(); +#endif SaveTape(tape.level_nr); /* ask to save tape */ } @@ -7207,7 +7228,7 @@ void EdelsteinFunkeln(int x, int y) return; if (MovDelay[x][y] == 0) /* next animation frame */ - MovDelay[x][y] = 11 * !SimpleRND(500); + MovDelay[x][y] = 11 * !GetSimpleRandom(500); if (MovDelay[x][y] != 0) /* wait some time before next frame */ { @@ -8672,11 +8693,11 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) player->frame_counter_bored = FrameCounter + game.player_boring_delay_fixed + - SimpleRND(game.player_boring_delay_random); + GetSimpleRandom(game.player_boring_delay_random); player->frame_counter_sleeping = FrameCounter + game.player_sleeping_delay_fixed + - SimpleRND(game.player_sleeping_delay_random); + GetSimpleRandom(game.player_sleeping_delay_random); InitPlayerGfxAnimation(player, ACTION_WAITING, move_dir); } @@ -8732,10 +8753,10 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) player->anim_delay_counter = graphic_info[special_graphic].anim_delay_fixed + - SimpleRND(graphic_info[special_graphic].anim_delay_random); + GetSimpleRandom(graphic_info[special_graphic].anim_delay_random); player->post_delay_counter = graphic_info[special_graphic].post_delay_fixed + - SimpleRND(graphic_info[special_graphic].post_delay_random); + GetSimpleRandom(graphic_info[special_graphic].post_delay_random); player->special_action_sleeping = special_action; } @@ -8758,16 +8779,16 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) if (player->anim_delay_counter == 0 && player->post_delay_counter == 0) { int special_action = - ACTION_BORING_1 + SimpleRND(player->num_special_action_bored); + ACTION_BORING_1 + GetSimpleRandom(player->num_special_action_bored); int special_graphic = el_act_dir2img(player->artwork_element, special_action, move_dir); player->anim_delay_counter = graphic_info[special_graphic].anim_delay_fixed + - SimpleRND(graphic_info[special_graphic].anim_delay_random); + GetSimpleRandom(graphic_info[special_graphic].anim_delay_random); player->post_delay_counter = graphic_info[special_graphic].post_delay_fixed + - SimpleRND(graphic_info[special_graphic].post_delay_random); + GetSimpleRandom(graphic_info[special_graphic].post_delay_random); player->special_action_bored = special_action; } @@ -12412,6 +12433,312 @@ void RequestQuitGame(boolean ask_if_really_quit) } +/* ------------------------------------------------------------------------- */ +/* random generator functions */ +/* ------------------------------------------------------------------------- */ + +unsigned int InitEngineRandom_RND(long seed) +{ + game.num_random_calls = 0; + +#if 0 + unsigned int rnd_seed = InitEngineRandom(seed); + + printf("::: START RND: %d\n", rnd_seed); + + return rnd_seed; +#else + + return InitEngineRandom(seed); + +#endif + +} + +unsigned int RND(int max) +{ + if (max > 0) + { + game.num_random_calls++; + + return GetEngineRandom(max); + } + + return 0; +} + + +/* ------------------------------------------------------------------------- */ +/* game engine snapshot handling functions */ +/* ------------------------------------------------------------------------- */ + +#define ARGS_ADDRESS_AND_SIZEOF(x) (&(x)), (sizeof(x)) + +struct EngineSnapshotInfo +{ + /* runtime values for custom element collect score */ + int collect_score[NUM_CUSTOM_ELEMENTS]; + + /* runtime values for group element choice position */ + int choice_pos[NUM_GROUP_ELEMENTS]; + + /* runtime values for belt position animations */ + int belt_graphic[4 * NUM_BELT_PARTS]; + int belt_anim_mode[4 * NUM_BELT_PARTS]; +}; + +struct EngineSnapshotNodeInfo +{ + void *buffer_orig; + void *buffer_copy; + int size; +}; + +static struct EngineSnapshotInfo engine_snapshot_rnd; +static ListNode *engine_snapshot_list = NULL; +static char *snapshot_level_identifier = NULL; +static int snapshot_level_nr = -1; + +void FreeEngineSnapshot() +{ + while (engine_snapshot_list != NULL) + deleteNodeFromList(&engine_snapshot_list, engine_snapshot_list->key, + checked_free); + + setString(&snapshot_level_identifier, NULL); + snapshot_level_nr = -1; +} + +static void SaveEngineSnapshotValues_RND() +{ + static int belt_base_active_element[4] = + { + EL_CONVEYOR_BELT_1_LEFT_ACTIVE, + EL_CONVEYOR_BELT_2_LEFT_ACTIVE, + EL_CONVEYOR_BELT_3_LEFT_ACTIVE, + EL_CONVEYOR_BELT_4_LEFT_ACTIVE + }; + int i, j; + + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + + engine_snapshot_rnd.collect_score[i] = element_info[element].collect_score; + } + + for (i = 0; i < NUM_GROUP_ELEMENTS; i++) + { + int element = EL_GROUP_START + i; + + engine_snapshot_rnd.choice_pos[i] = element_info[element].group->choice_pos; + } + + for (i = 0; i < 4; i++) + { + for (j = 0; j < NUM_BELT_PARTS; j++) + { + int element = belt_base_active_element[i] + j; + int graphic = el2img(element); + int anim_mode = graphic_info[graphic].anim_mode; + + engine_snapshot_rnd.belt_graphic[i * 4 + j] = graphic; + engine_snapshot_rnd.belt_anim_mode[i * 4 + j] = anim_mode; + } + } +} + +static void LoadEngineSnapshotValues_RND() +{ + unsigned long num_random_calls = game.num_random_calls; + int i, j; + + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + + element_info[element].collect_score = engine_snapshot_rnd.collect_score[i]; + } + + for (i = 0; i < NUM_GROUP_ELEMENTS; i++) + { + int element = EL_GROUP_START + i; + + element_info[element].group->choice_pos = engine_snapshot_rnd.choice_pos[i]; + } + + for (i = 0; i < 4; i++) + { + for (j = 0; j < NUM_BELT_PARTS; j++) + { + int graphic = engine_snapshot_rnd.belt_graphic[i * 4 + j]; + int anim_mode = engine_snapshot_rnd.belt_anim_mode[i * 4 + j]; + + graphic_info[graphic].anim_mode = anim_mode; + } + } + + if (level.game_engine_type == GAME_ENGINE_TYPE_RND) + { + InitRND(tape.random_seed); + for (i = 0; i < num_random_calls; i++) + RND(1); + } + + if (game.num_random_calls != num_random_calls) + { + Error(ERR_RETURN, "number of random calls out of sync"); + Error(ERR_RETURN, "number of random calls should be %d", num_random_calls); + Error(ERR_RETURN, "number of random calls is %d", game.num_random_calls); + Error(ERR_EXIT, "this should not happen -- please debug"); + } +} + +static void SaveEngineSnapshotBuffer(void *buffer, int size) +{ + struct EngineSnapshotNodeInfo *bi = + checked_calloc(sizeof(struct EngineSnapshotNodeInfo)); + + bi->buffer_orig = buffer; + bi->buffer_copy = checked_malloc(size); + bi->size = size; + + memcpy(bi->buffer_copy, buffer, size); + + addNodeToList(&engine_snapshot_list, NULL, bi); +} + +void SaveEngineSnapshot() +{ + FreeEngineSnapshot(); /* free previous snapshot, if needed */ + + /* copy some special values to a structure better suited for the snapshot */ + + SaveEngineSnapshotValues_RND(); + SaveEngineSnapshotValues_EM(); + + /* save values stored in special snapshot structure */ + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em)); + + /* save further RND engine values */ + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(stored_player)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(game)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(tape)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ZX)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ZY)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExitX)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExitY)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FrameCounter)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimeFrames)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimePlayed)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimeLeft)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TapeTime)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenMovDir)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenMovPos)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenGfxPos)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollStepSize)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AllPlayersGone)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt2)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Feld)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovPos)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovDir)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovDelay)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeDelay)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangePage)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CustomValue)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Store)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Store2)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(StorePlayer)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Back)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaNr)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustMoving)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustFalling)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CheckCollision)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Stop)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Pushed)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeCount)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeEvent)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodePhase)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodeDelay)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodeField)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RunnerVisit)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(PlayerVisit)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxFrame)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxRandom)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxElement)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxAction)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxDir)); + + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(scroll_x)); + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(scroll_y)); + + /* save level identification information */ + + setString(&snapshot_level_identifier, leveldir_current->identifier); + snapshot_level_nr = level_nr; + +#if 0 + ListNode *node = engine_snapshot_list; + int num_bytes = 0; + + while (node != NULL) + { + num_bytes += ((struct EngineSnapshotNodeInfo *)node->content)->size; + + node = node->next; + } + + printf("::: size of engine snapshot: %d bytes\n", num_bytes); +#endif +} + +static void LoadEngineSnapshotBuffer(struct EngineSnapshotNodeInfo *bi) +{ + memcpy(bi->buffer_orig, bi->buffer_copy, bi->size); +} + +void LoadEngineSnapshot() +{ + ListNode *node = engine_snapshot_list; + + if (engine_snapshot_list == NULL) + return; + + while (node != NULL) + { + LoadEngineSnapshotBuffer((struct EngineSnapshotNodeInfo *)node->content); + + node = node->next; + } + + /* restore special values from snapshot structure */ + + LoadEngineSnapshotValues_RND(); + LoadEngineSnapshotValues_EM(); +} + +boolean CheckEngineSnapshot() +{ + return (strEqual(snapshot_level_identifier, leveldir_current->identifier) && + snapshot_level_nr == level_nr); +} + + /* ---------- new game button stuff ---------------------------------------- */ /* graphic position values for game buttons */ diff --git a/src/game.h b/src/game.h index 57621e88..45323679 100644 --- a/src/game.h +++ b/src/game.h @@ -86,6 +86,9 @@ struct GameInfo int centered_player_nr; int centered_player_nr_next; boolean set_centered_player; + + /* values for random number generator initialization after snapshot */ + unsigned long num_random_calls; }; struct PlayerInfo @@ -199,9 +202,8 @@ struct PlayerInfo int inventory_size; }; - extern struct GameInfo game; -extern struct PlayerInfo stored_player[], *local_player; +extern struct PlayerInfo stored_player[MAX_PLAYERS], *local_player; #ifdef DEBUG @@ -240,6 +242,14 @@ void RaiseScore(int); void RaiseScoreElement(int); void RequestQuitGame(boolean); +unsigned int InitEngineRandom_RND(long); +unsigned int RND(int); + +void FreeEngineSnapshot(); +void LoadEngineSnapshot(); +void SaveEngineSnapshot(); +boolean CheckEngineSnapshot(); + void CreateGameButtons(); void FreeGameButtons(); void UnmapGameButtons(); diff --git a/src/game_em/export.h b/src/game_em/export.h index e7cfae0e..20987253 100644 --- a/src/game_em/export.h +++ b/src/game_em/export.h @@ -691,6 +691,22 @@ struct GraphicInfo_EM int unique_identifier; /* used to identify needed screen updates */ }; +struct EngineSnapshotInfo_EM +{ + struct GameInfo_EM game_em; + unsigned long RandomEM; + struct LEVEL lev; + struct PLAYER ply[MAX_PLAYERS]; + short Array[4][EM_MAX_CAVE_HEIGHT][EM_MAX_CAVE_WIDTH]; + int screen_x; + int screen_y; + int frame; + short **Boom; + short **Cave; + short **Next; + short **Draw; +}; + /* ------------------------------------------------------------------------- */ /* exported functions */ @@ -700,6 +716,7 @@ extern struct GlobalInfo_EM global_em_info; extern struct LevelInfo_EM native_em_level; extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8]; extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8]; +extern struct EngineSnapshotInfo_EM engine_snapshot_em; extern void em_open_all(); extern void em_close_all(); @@ -707,7 +724,7 @@ extern void em_close_all(); extern void InitGameEngine_EM(); extern void GameActions_EM(byte *, boolean); -extern unsigned int InitEngineRND_EM(long); +extern unsigned int InitEngineRandom_EM(long); extern void setLevelInfoToDefaults_EM(); extern boolean LoadNativeLevel_EM(char *); @@ -717,4 +734,7 @@ extern void BlitScreenToBitmap_EM(Bitmap *); extern void RedrawPlayfield_EM(boolean); extern void DrawGameDoorValues_EM(); +extern void LoadEngineSnapshotValues_EM(); +extern void SaveEngineSnapshotValues_EM(); + #endif /* EXPORT_H */ diff --git a/src/game_em/init.c b/src/game_em/init.c index a756d24a..b5a0e033 100644 --- a/src/game_em/init.c +++ b/src/game_em/init.c @@ -369,11 +369,11 @@ void sound_play(void) memset(play, 0, sizeof(play)); } -unsigned int InitEngineRND_EM(long seed) +unsigned int InitEngineRandom_EM(long seed) { if (seed == NEW_RANDOMIZE) { - int simple_rnd = SimpleRND(1000); + int simple_rnd = GetSimpleRandom(1000); int i; for (i = 0; i < simple_rnd || RandomEM == NEW_RANDOMIZE; i++) diff --git a/src/game_em/input.c b/src/game_em/input.c index 0dd2bb3b..cc703ba9 100644 --- a/src/game_em/input.c +++ b/src/game_em/input.c @@ -22,6 +22,8 @@ static short Array[4][HEIGHT][WIDTH]; extern int screen_x; extern int screen_y; +struct EngineSnapshotInfo_EM engine_snapshot_em; + void game_init_vars(void) { int x, y; @@ -160,3 +162,57 @@ void readjoy(byte action, struct PLAYER *ply) ply->joy_w = west; } } + +void SaveEngineSnapshotValues_EM() +{ + int i, j, k; + + engine_snapshot_em.game_em = game_em; + engine_snapshot_em.lev = lev; + + engine_snapshot_em.RandomEM = RandomEM; + engine_snapshot_em.frame = frame; + + engine_snapshot_em.screen_x = screen_x; + engine_snapshot_em.screen_y = screen_y; + + engine_snapshot_em.Boom = Boom; + engine_snapshot_em.Cave = Cave; + engine_snapshot_em.Next = Next; + engine_snapshot_em.Draw = Draw; + + for (i = 0; i < 4; i++) + engine_snapshot_em.ply[i] = ply[i]; + + for (i = 0; i < 4; i++) + for (j = 0; j < HEIGHT; j++) + for (k = 0; k < WIDTH; k++) + engine_snapshot_em.Array[i][j][k] = Array[i][j][k]; +} + +void LoadEngineSnapshotValues_EM() +{ + int i, j, k; + + game_em = engine_snapshot_em.game_em; + lev = engine_snapshot_em.lev; + + RandomEM = engine_snapshot_em.RandomEM; + frame = engine_snapshot_em.frame; + + screen_x = engine_snapshot_em.screen_x; + screen_y = engine_snapshot_em.screen_y; + + Boom = engine_snapshot_em.Boom; + Cave = engine_snapshot_em.Cave; + Next = engine_snapshot_em.Next; + Draw = engine_snapshot_em.Draw; + + for (i = 0; i < 4; i++) + ply[i] = engine_snapshot_em.ply[i]; + + for (i = 0; i < 4; i++) + for (j = 0; j < HEIGHT; j++) + for (k = 0; k < WIDTH; k++) + Array[i][j][k] = engine_snapshot_em.Array[i][j][k]; +} diff --git a/src/init.c b/src/init.c index f5581896..eb6b0374 100644 --- a/src/init.c +++ b/src/init.c @@ -4762,7 +4762,7 @@ void OpenAll() InitCounter(); InitRND(NEW_RANDOMIZE); - InitSimpleRND(NEW_RANDOMIZE); + InitSimpleRandom(NEW_RANDOMIZE); InitJoysticks(); diff --git a/src/libgame/misc.c b/src/libgame/misc.c index f9ec87fe..ae54541f 100644 --- a/src/libgame/misc.c +++ b/src/libgame/misc.c @@ -1544,7 +1544,7 @@ void deleteNodeFromList(ListNode **node_first, char *key, if (strEqual((*node_first)->key, key)) { - free((*node_first)->key); + checked_free((*node_first)->key); if (destructor_function) destructor_function((*node_first)->content); *node_first = (*node_first)->next; diff --git a/src/libgame/misc.h b/src/libgame/misc.h index 1bafb463..009350c0 100644 --- a/src/libgame/misc.h +++ b/src/libgame/misc.h @@ -27,10 +27,13 @@ /* values for InitRND() */ #define NEW_RANDOMIZE -1 -#define InitEngineRND(seed) init_random_number(0, seed) -#define InitSimpleRND(seed) init_random_number(1, seed) -#define RND(max) get_random_number(0, max) -#define SimpleRND(max) get_random_number(1, max) +#define RANDOM_ENGINE 0 +#define RANDOM_SIMPLE 1 + +#define InitEngineRandom(seed) init_random_number(RANDOM_ENGINE, seed) +#define InitSimpleRandom(seed) init_random_number(RANDOM_SIMPLE, seed) +#define GetEngineRandom(max) get_random_number(RANDOM_ENGINE, max) +#define GetSimpleRandom(max) get_random_number(RANDOM_SIMPLE, max) /* values for Error() */ #define ERR_RETURN 0 diff --git a/src/libgame/toons.c b/src/libgame/toons.c index 0b7ca552..c5f1ff39 100644 --- a/src/libgame/toons.c +++ b/src/libgame/toons.c @@ -65,7 +65,7 @@ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame, /* note: expect different frames for the same delay cycle! */ if (gfx.anim_random_frame < 0) - frame = SimpleRND(num_frames); + frame = GetSimpleRandom(num_frames); else frame = gfx.anim_random_frame % num_frames; } @@ -182,11 +182,11 @@ boolean AnimateToon(int toon_nr, boolean restart) else if (strEqual(anim->position, "bottom")) pos_y = pos_bottom; else if (strEqual(anim->position, "upper")) - pos_y = SimpleRND(pos_bottom / 2); + pos_y = GetSimpleRandom(pos_bottom / 2); else if (strEqual(anim->position, "lower")) - pos_y = pos_bottom / 2 + SimpleRND(pos_bottom / 2); + pos_y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2); else - pos_y = SimpleRND(pos_bottom); + pos_y = GetSimpleRandom(pos_bottom); if (direction == MV_RIGHT) { @@ -210,7 +210,7 @@ boolean AnimateToon(int toon_nr, boolean restart) else if (strEqual(anim->position, "right")) pos_x = pos_right; else - pos_x = SimpleRND(pos_right); + pos_x = GetSimpleRandom(pos_right); if (direction == MV_DOWN) { @@ -354,7 +354,7 @@ void HandleAnimation(int mode) if (reset_delay) { animstart_delay = Counter(); - animstart_delay_value = SimpleRND(3000); + animstart_delay_value = GetSimpleRandom(3000); reset_delay = FALSE; } @@ -363,7 +363,7 @@ void HandleAnimation(int mode) if (!DelayReached(&animstart_delay, animstart_delay_value)) return; - toon_nr = SimpleRND(screen_info.num_toons); + toon_nr = GetSimpleRandom(screen_info.num_toons); } anim_restart = reset_delay = AnimateToon(toon_nr, anim_restart); diff --git a/src/main.c b/src/main.c index ccf8e42a..25bdd22b 100644 --- a/src/main.c +++ b/src/main.c @@ -3695,43 +3695,43 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] = "growing wall (horizontal, BD style)" }, { - "last_ce_8", - "last_ce", + "prev_ce_8", + "prev_ce", "CE 8 positions earlier in list" }, { - "last_ce_7", - "last_ce", + "prev_ce_7", + "prev_ce", "CE 7 positions earlier in list" }, { - "last_ce_6", - "last_ce", + "prev_ce_6", + "prev_ce", "CE 6 positions earlier in list" }, { - "last_ce_5", - "last_ce", + "prev_ce_5", + "prev_ce", "CE 5 positions earlier in list" }, { - "last_ce_4", - "last_ce", + "prev_ce_4", + "prev_ce", "CE 4 positions earlier in list" }, { - "last_ce_3", - "last_ce", + "prev_ce_3", + "prev_ce", "CE 3 positions earlier in list" }, { - "last_ce_2", - "last_ce", + "prev_ce_2", + "prev_ce", "CE 2 positions earlier in list" }, { - "last_ce_1", - "last_ce", + "prev_ce_1", + "prev_ce", "CE 1 position earlier in list" }, { diff --git a/src/main.h b/src/main.h index 9ba274dd..893d8d8f 100644 --- a/src/main.h +++ b/src/main.h @@ -1303,14 +1303,14 @@ #define EL_BD_EXPANDABLE_WALL 713 -#define EL_LAST_CE_8 714 -#define EL_LAST_CE_7 715 -#define EL_LAST_CE_6 716 -#define EL_LAST_CE_5 717 -#define EL_LAST_CE_4 718 -#define EL_LAST_CE_3 719 -#define EL_LAST_CE_2 720 -#define EL_LAST_CE_1 721 +#define EL_PREV_CE_8 714 +#define EL_PREV_CE_7 715 +#define EL_PREV_CE_6 716 +#define EL_PREV_CE_5 717 +#define EL_PREV_CE_4 718 +#define EL_PREV_CE_3 719 +#define EL_PREV_CE_2 720 +#define EL_PREV_CE_1 721 #define EL_SELF 722 #define EL_NEXT_CE_1 723 #define EL_NEXT_CE_2 724 @@ -1727,7 +1727,7 @@ /* program information and versioning definitions */ #define PROGRAM_VERSION_MAJOR 3 #define PROGRAM_VERSION_MINOR 2 -#define PROGRAM_VERSION_PATCH 1 +#define PROGRAM_VERSION_PATCH 2 #define PROGRAM_VERSION_BUILD 0 #define PROGRAM_TITLE_STRING "Rocks'n'Diamonds" @@ -2397,8 +2397,6 @@ extern int ExitX, ExitY; extern int AllPlayersGone; extern int TimeFrames, TimePlayed, TimeLeft, TapeTime; -extern boolean SiebAktiv; -extern int SiebCount; extern boolean network_player_action_received; diff --git a/src/tape.c b/src/tape.c index 1259c0d5..eb03967a 100644 --- a/src/tape.c +++ b/src/tape.c @@ -677,6 +677,9 @@ void TapeTogglePause(boolean toggle_manual) tape.quick_resume = FALSE; TapeAppendRecording(); + + if (!CheckEngineSnapshot()) + SaveEngineSnapshot(); } } } @@ -902,18 +905,25 @@ static void TapeSingleStep() void TapeQuickSave() { - if (game_status == GAME_MODE_PLAYING) + if (game_status == GAME_MODE_MAIN) { - if (tape.recording) - TapeHaltRecording(); /* prepare tape for saving on-the-fly */ + Request("No game that can be saved !", REQ_CONFIRM); - if (TAPE_IS_EMPTY(tape)) - Request("No tape that can be saved !", REQ_CONFIRM); - else - SaveTape(tape.level_nr); + return; } - else if (game_status == GAME_MODE_MAIN) - Request("No game that can be saved !", REQ_CONFIRM); + + if (game_status != GAME_MODE_PLAYING) + return; + + if (tape.recording) + TapeHaltRecording(); /* prepare tape for saving on-the-fly */ + + if (TAPE_IS_EMPTY(tape)) + Request("No tape that can be saved !", REQ_CONFIRM); + else + SaveTape(tape.level_nr); + + SaveEngineSnapshot(); } void TapeQuickLoad() @@ -935,25 +945,42 @@ void TapeQuickLoad() return; } - if (game_status == GAME_MODE_PLAYING || game_status == GAME_MODE_MAIN) + if (game_status != GAME_MODE_PLAYING && game_status != GAME_MODE_MAIN) + return; + + if (CheckEngineSnapshot()) { - TapeStop(); - TapeErase(); + TapeStartGamePlaying(); - LoadTape(level_nr); - if (!TAPE_IS_EMPTY(tape)) - { - TapeStartGamePlaying(); - TapeStartWarpForward(); + LoadEngineSnapshot(); - tape.quick_resume = TRUE; - } - else /* this should not happen (basically checked above) */ - { - int reopen_door = (game_status == GAME_MODE_PLAYING ? REQ_REOPEN : 0); + tape.playing = TRUE; + tape.pausing = TRUE; - Request("No tape for this level !", REQ_CONFIRM | reopen_door); - } + TapeStopWarpForward(); + TapeAppendRecording(); + + if (FrameCounter > 0) + return; + } + + TapeStop(); + TapeErase(); + + LoadTape(level_nr); + + if (!TAPE_IS_EMPTY(tape)) + { + TapeStartGamePlaying(); + TapeStartWarpForward(); + + tape.quick_resume = TRUE; + } + else /* this should not happen (basically checked above) */ + { + int reopen_door = (game_status == GAME_MODE_PLAYING ? REQ_REOPEN : 0); + + Request("No tape for this level !", REQ_CONFIRM | reopen_door); } } diff --git a/src/tools.c b/src/tools.c index 298a98bf..7a2fd3e2 100644 --- a/src/tools.c +++ b/src/tools.c @@ -138,7 +138,6 @@ void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height) level.game_engine_type == GAME_ENGINE_TYPE_EM) { /* currently there is no partial redraw -- always redraw whole playfield */ - RedrawPlayfield_EM(TRUE); /* blit playfield from scroll buffer to normal back buffer for fading in */ @@ -184,6 +183,14 @@ void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height) } } + if (force_redraw) + { + x = gfx.sx; + y = gfx.sy; + width = gfx.sxsize; + height = gfx.sysize; + } + BlitBitmap(drawto, window, x, y, width, height, x, y); } @@ -2226,6 +2233,10 @@ void WaitForEventToContinue() button_status = MB_RELEASED; +#if 1 + ClearEventQueue(); +#endif + while (still_wait) { if (PendingEvent()) @@ -5306,9 +5317,9 @@ int getGameFrameDelay_EM(int native_em_game_frame_delay) unsigned int InitRND(long seed) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - return InitEngineRND_EM(seed); + return InitEngineRandom_EM(seed); else - return InitEngineRND(seed); + return InitEngineRandom_RND(seed); } void InitGraphicInfo_EM(void)