+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
(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
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,
{ "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" },
#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
-#define COMPILE_DATE_STRING "[2006-08-20 20:05]"
+#define COMPILE_DATE_STRING "[2006-08-29 23:29]"
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,
break;
case EVENT_KEYRELEASE:
+#if 1
+ ClearPlayerAction();
+#else
key_joystick_mapping = 0;
+#endif
break;
default:
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();
if (tape.playing || keyboard)
newbutton = ((joy & JOY_BUTTON) != 0);
+#if 1
+ if (local_player->LevelSolved_GameEnd && newbutton)
+#else
if (AllPlayersGone && newbutton)
+#endif
{
GameEnd();
#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))
(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))
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;
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);
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);
}
if (local_player->LevelSolved_SaveTape)
{
+#if 0
TapeStop();
+#endif
SaveTape(tape.level_nr); /* ask to save tape */
}
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 */
{
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);
}
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;
}
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;
}
}
+/* ------------------------------------------------------------------------- */
+/* 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 */
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
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
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();
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 */
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();
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 *);
extern void RedrawPlayfield_EM(boolean);
extern void DrawGameDoorValues_EM();
+extern void LoadEngineSnapshotValues_EM();
+extern void SaveEngineSnapshotValues_EM();
+
#endif /* EXPORT_H */
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++)
extern int screen_x;
extern int screen_y;
+struct EngineSnapshotInfo_EM engine_snapshot_em;
+
void game_init_vars(void)
{
int x, y;
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];
+}
InitCounter();
InitRND(NEW_RANDOMIZE);
- InitSimpleRND(NEW_RANDOMIZE);
+ InitSimpleRandom(NEW_RANDOMIZE);
InitJoysticks();
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;
/* 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
/* 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;
}
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)
{
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)
{
if (reset_delay)
{
animstart_delay = Counter();
- animstart_delay_value = SimpleRND(3000);
+ animstart_delay_value = GetSimpleRandom(3000);
reset_delay = FALSE;
}
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);
"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"
},
{
#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
/* 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"
extern int AllPlayersGone;
extern int TimeFrames, TimePlayed, TimeLeft, TapeTime;
-extern boolean SiebAktiv;
-extern int SiebCount;
extern boolean network_player_action_received;
tape.quick_resume = FALSE;
TapeAppendRecording();
+
+ if (!CheckEngineSnapshot())
+ SaveEngineSnapshot();
}
}
}
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()
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);
}
}
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 */
}
}
+ if (force_redraw)
+ {
+ x = gfx.sx;
+ y = gfx.sy;
+ width = gfx.sxsize;
+ height = gfx.sysize;
+ }
+
BlitBitmap(drawto, window, x, y, width, height, x, y);
}
button_status = MB_RELEASED;
+#if 1
+ ClearEventQueue();
+#endif
+
while (still_wait)
{
if (PendingEvent())
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)