<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="application/zip" />
+ </intent-filter>
</activity>
</application>
import org.libsdl.app.SDLActivity;
-public class rocksndiamonds extends SDLActivity { }
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.provider.OpenableColumns;
+import android.util.Log;
+
+public class rocksndiamonds extends SDLActivity {
+ private static final String TAG = "RND";
+ private String[] args;
+
+ @Override
+ protected String[] getArguments() {
+ return args;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ Log.d(TAG, "onCreate");
+
+ // init program arguments
+ args = new String[0];
+
+ // prevent SDL from sending "drop file" event on app start; use program arguments instead
+ Intent intent = getIntent();
+ handleIntent(intent, true);
+ intent.setData(null);
+
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ Log.d(TAG, "onNewIntent");
+
+ // handle file opened with "open with" when app is already running
+ handleIntent(intent, false);
+ }
+
+ private void handleIntent(Intent intent, boolean onCreate) {
+ Log.d(TAG, "handleIntent");
+
+ Uri uri = intent.getData();
+ if (uri == null) {
+ Log.d(TAG, "handleIntent: uri == null");
+ return;
+ }
+
+ if (onCreate) {
+ Log.d(TAG, "handleIntent: starting app with file as argument");
+
+ // app not running yet -- starting app with "--drop-file" argument
+ setProgramArgs(uri);
+ } else {
+ Log.d(TAG, "handleIntent: sending drop event to running app");
+
+ // app already running -- sending file as a "drop file" event
+ sendUriAsDroppedFile(uri);
+ }
+ }
+
+ public void sendUriAsDroppedFile(Uri uri) {
+ SDLActivity.onNativeDropFile(getFileDescriptorStringFromUri(uri));
+ }
+
+ private int getFileDescriptorFromUri(Uri uri) {
+ int fd = -1;
+
+ try {
+ ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, "r");
+ if (pfd == null) {
+ throw new RuntimeException("pfd is null");
+ }
+
+ fd = pfd.dup().detachFd();
+ pfd.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to convert URI " + uri.toString() + " to file descriptor", e);
+ }
+
+ return fd;
+ }
+
+ private String getFileDescriptorStringFromUri(Uri uri) {
+ return "fd:" + getFileDescriptorFromUri(uri);
+ }
+
+ private void setProgramArgs(Uri uri) {
+ Log.d(TAG, "setProgramArgs");
+
+ // log some file details
+ Cursor returnCursor = getContentResolver().query(uri, null, null, null, null);
+ int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
+ int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
+ returnCursor.moveToFirst();
+ Log.e(TAG, "setProgramArgs: file name: " + returnCursor.getString(nameIndex));
+ Log.e(TAG, "setProgramArgs: file size: " + Long.toString(returnCursor.getLong(sizeIndex)));
+
+ String scheme = uri.getScheme();
+ if (scheme != null) {
+ if (scheme.equals("content")) {
+ // convert URI to file descriptor
+ String fd = getFileDescriptorStringFromUri(uri);
+ Log.e(TAG, "setProgramArgs: setting argument to file descriptor: " + fd);
+ args = new String[]{ "--drop-file", fd };
+ } else if (scheme.equals("file")) {
+ // directly use regular file
+ String path = uri.getPath();
+ Log.e(TAG, "setProgramArgs: setting argument to file path: " + path);
+ args = new String[]{ "--drop-file", path };
+ }
+ }
+ }
+}
# =============================================================================
# Rocks'n'Diamonds - McDuffin Strikes Back!
# -----------------------------------------------------------------------------
-# (c) 1995-2014 by Artsoft Entertainment
+# (c) 1995-2024 by Artsoft Entertainment
# Holger Schemel
# info@artsoft.org
# https://www.artsoft.org/
libgame/image.c \
libgame/random.c \
libgame/hash.c \
+ libgame/list.c \
libgame/http.c \
libgame/base64.c \
libgame/setup.c \
libgame/zip/iowin32.c \
libgame/zip/unzip.c \
libgame/zip/miniunz.c \
+ game_bd/main_bd.c \
+ game_bd/bd_cave.c \
+ game_bd/bd_cavedb.c \
+ game_bd/bd_caveengine.c \
+ game_bd/bd_caveobject.c \
+ game_bd/bd_bdcff.c \
+ game_bd/bd_caveset.c \
+ game_bd/bd_c64import.c \
+ game_bd/bd_gameplay.c \
+ game_bd/bd_graphics.c \
+ game_bd/bd_colors.c \
+ game_bd/bd_random.c \
+ game_bd/bd_sound.c \
game_em/cave.c \
game_em/convert.c \
game_em/graphics.c \
{ "[bdx_default].growing.delay", "4" },
{ "[bdx_default].growing.anim_mode", "linear" },
+ { "bdx_empty_space", UNDEFINED_FILENAME },
+ { "bdx_empty_space.clone_from", "empty_space" },
+
{ "bdx_player", UNDEFINED_FILENAME },
{ "bdx_player.clone_from", "player_1" },
{ "bdx_player.down", UNDEFINED_FILENAME },
{ "bdx_steelwall_sloped_down_right.frames", "1" },
{ "bdx_steelwall_explodable", UNDEFINED_FILENAME },
- { "bdx_steelwall_explodable.clone_from", "bd_steelwall" },
+ { "bdx_steelwall_explodable.clone_from", "bdx_steelwall" },
{ "bdx_steelwall_diggable", UNDEFINED_FILENAME },
- { "bdx_steelwall_diggable.clone_from", "bd_steelwall" },
+ { "bdx_steelwall_diggable.clone_from", "bdx_steelwall" },
{ "bdx_steelwall_diggable.EDITOR", "RocksBD2.png" },
{ "bdx_steelwall_diggable.EDITOR.xpos", "6" },
{ "bdx_steelwall_diggable.EDITOR.ypos", "0" },
{ "bdx_expandable_wall_any.EDITOR.ypos", "1" },
{ "bdx_expandable_steelwall_horizontal", UNDEFINED_FILENAME },
- { "bdx_expandable_steelwall_horizontal.clone_from", "bd_steelwall" },
+ { "bdx_expandable_steelwall_horizontal.clone_from", "bdx_steelwall" },
{ "bdx_expandable_steelwall_horizontal.EDITOR", "RocksBD2.png" },
{ "bdx_expandable_steelwall_horizontal.EDITOR.xpos", "0" },
{ "bdx_expandable_steelwall_horizontal.EDITOR.ypos", "1" },
{ "bdx_expandable_steelwall_vertical", UNDEFINED_FILENAME },
- { "bdx_expandable_steelwall_vertical.clone_from", "bd_steelwall" },
+ { "bdx_expandable_steelwall_vertical.clone_from", "bdx_steelwall" },
{ "bdx_expandable_steelwall_vertical.EDITOR", "RocksBD2.png" },
{ "bdx_expandable_steelwall_vertical.EDITOR.xpos", "1" },
{ "bdx_expandable_steelwall_vertical.EDITOR.ypos", "1" },
{ "bdx_expandable_steelwall_any", UNDEFINED_FILENAME },
- { "bdx_expandable_steelwall_any.clone_from", "bd_steelwall" },
+ { "bdx_expandable_steelwall_any.clone_from", "bdx_steelwall" },
{ "bdx_expandable_steelwall_any.EDITOR", "RocksBD2.png" },
{ "bdx_expandable_steelwall_any.EDITOR.xpos", "2" },
{ "bdx_expandable_steelwall_any.EDITOR.ypos", "1" },
{ "bdx_exit_open.EDITOR.ypos", "0" },
{ "bdx_invisible_exit_closed", UNDEFINED_FILENAME },
- { "bdx_invisible_exit_closed.clone_from", "bd_steelwall" },
+ { "bdx_invisible_exit_closed.clone_from", "bdx_steelwall" },
{ "bdx_invisible_exit_closed.EDITOR", "RocksBD2.png" },
{ "bdx_invisible_exit_closed.EDITOR.xpos", "4" },
{ "bdx_invisible_exit_closed.EDITOR.ypos", "0" },
{ "bdx_invisible_exit_open", UNDEFINED_FILENAME },
- { "bdx_invisible_exit_open.clone_from", "bd_steelwall" },
+ { "bdx_invisible_exit_open.clone_from", "bdx_steelwall" },
{ "bdx_invisible_exit_open.EDITOR", "RocksBD2.png" },
{ "bdx_invisible_exit_open.EDITOR.xpos", "2" },
{ "bdx_invisible_exit_open.EDITOR.ypos", "0" },
{ "[sp_default].exploding.delay", "4" },
{ "[sp_default].exploding.anim_mode", "linear" },
+ { "sp_empty_space", UNDEFINED_FILENAME },
+ { "sp_empty_space.clone_from", "empty_space" },
+
{ "sp_zonk", "RocksSP.png" },
{ "sp_zonk.xpos", "1" },
{ "sp_zonk.ypos", "0" },
{ "emc_dripper.active.ypos", "8" },
{ "emc_dripper.active.frames", "1" },
+ { "mm_empty_space", UNDEFINED_FILENAME },
+ { "mm_empty_space.clone_from", "empty_space" },
+
{ "mm_mcduffin", "RocksMM.png" },
{ "mm_mcduffin.xpos", "4" },
{ "mm_mcduffin.ypos", "1" },
{ "[mm_default].exploding.delay", "2" },
{ "[mm_default].exploding.anim_mode", "linear" },
+ { "df_empty_space", UNDEFINED_FILENAME },
+ { "df_empty_space.clone_from", "empty_space" },
+
{ "df_laser", "RocksDF.png" },
{ "df_laser.xpos", "0" },
{ "df_laser.ypos", "9" },
{ "bd_firefly.waiting", "roehr.wav" },
// sounds for Boulder Dash style elements and actions (native game engine)
- { "bdx_sand_ball.falling", UNDEFINED_FILENAME },
+ { "bdx_sand_ball.falling", "schlurf.wav" },
{ "bdx_sand_ball.impact", "schlurf.wav" },
- { "bdx_sand_loose.falling", UNDEFINED_FILENAME },
+ { "bdx_sand_loose.falling", "schlurf.wav" },
{ "bdx_sand_loose.impact", "schlurf.wav" },
{ "bdx_diamond.collecting", "pong.wav" },
- { "bdx_diamond.falling", UNDEFINED_FILENAME },
+ { "bdx_diamond.falling", "pling.wav" },
{ "bdx_diamond.impact", "pling.wav" },
{ "bdx_flying_diamond.collecting", "pong.wav" },
- { "bdx_flying_diamond.falling", UNDEFINED_FILENAME },
+ { "bdx_flying_diamond.falling", "pling.wav" },
{ "bdx_flying_diamond.impact", "pling.wav" },
{ "bdx_rock.pushing", "pusch.wav" },
- { "bdx_rock.falling", UNDEFINED_FILENAME },
+ { "bdx_rock.falling", "klopf.wav" },
{ "bdx_rock.impact", "klopf.wav" },
{ "bdx_flying_rock.pushing", "pusch.wav" },
- { "bdx_flying_rock.falling", UNDEFINED_FILENAME },
+ { "bdx_flying_rock.falling", "klopf.wav" },
{ "bdx_flying_rock.impact", "klopf.wav" },
{ "bdx_mega_rock.pushing", "pusch.wav" },
- { "bdx_mega_rock.falling", UNDEFINED_FILENAME },
+ { "bdx_mega_rock.falling", "klopf.wav" },
{ "bdx_mega_rock.impact", "klopf.wav" },
{ "bdx_waiting_rock.pushing", "pusch.wav" },
{ "bdx_chasing_rock.pushing", "pusch.wav" },
{ "bdx_nut.pushing", "knurk.wav" },
{ "bdx_nut.breaking", "knack.wav" },
- { "bdx_nut.falling", UNDEFINED_FILENAME },
+ { "bdx_nut.falling", "klumpf.wav" },
{ "bdx_nut.impact", "klumpf.wav" },
{ "bdx_nitro_pack.pushing", "pusch.wav" },
{ "bdx_nitro_pack.impact", "klopf.wav" },
// functions
// ----------------------------------------------------------------------------
-boolean isLevelEditorTestGame(void)
+boolean isLevelEditorFastStart(void)
{
- return level_editor_test_game;
+ return (level_editor_test_game && setup.editor.fast_game_start);
}
static int getMaxInfoTextLength(void)
{
int i;
+ if (!hasColorTemplate_BD())
+ {
+ int font_nr = FONT_TEXT_1;
+ int font_height = getFontHeight(font_nr);
+ int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
+ int xpos = ED_ENGINE_SETTINGS_X(0);
+ int ypos = ED_ENGINE_SETTINGS_Y(0);
+
+ PrintInfoText("No level specific colors available.", font_nr, xpos, ypos - yoffset_above);
+ PrintInfoText("(Not supported by graphics set.)", font_nr, xpos, ypos);
+
+ return;
+ }
+
if (bd_color_type_changed)
{
if (level.bd_color_type != GD_COLOR_TYPE_RGB && level.bd_color_type != GetCommonColorType_BD())
#include "main.h"
-boolean isLevelEditorTestGame(void);
+boolean isLevelEditorFastStart(void);
void CreateLevelEditorGadgets(void);
void FreeLevelEditorGadgets(void);
Debug("event:dropfile", "filename == '%s'", filename);
// check and extract dropped zip files into correct user data directory
- if (!strSuffixLower(filename, ".zip"))
+ if (!strSuffixLower(filename, ".zip") &&
+ !strPrefixLower(filename, "fd:"))
{
Warn("file '%s' not supported", filename);
void HandleDropEvent(Event *event)
{
+ Debug("event:drop", (event->type == SDL_DROPBEGIN ? "SDL_DROPBEGIN" :
+ event->type == SDL_DROPFILE ? "SDL_DROPFILE" :
+ event->type == SDL_DROPTEXT ? "SDL_DROPTEXT" :
+ event->type == SDL_DROPCOMPLETE ? "SDL_DROPCOMPLETE" :
+ "(unknown drop event type)"));
+
static boolean confirm_on_drop_complete = FALSE;
static int num_level_sets_succeeded = 0;
static int num_artwork_sets_succeeded = 0;
{ &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
{ &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
};
+ boolean game_key_pressed = FALSE;
int joy = 0;
int i;
- if (HandleKeysSpeed(key, key_status))
- return; // do not handle already processed keys again
+ // check if any game key is pressed (direction/snap/drop keys)
+ if (game_status == GAME_MODE_PLAYING)
+ {
+ int pnr;
- if (HandleKeysDebug(key, key_status))
- return; // do not handle already processed keys again
+ for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
+ {
+ ski = setup.input[pnr].key;
+
+ for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
+ if (key == *key_info[i].key_custom)
+ game_key_pressed = TRUE;
+ }
+
+ ssi = setup.shortcut;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ if (key == *key_info[i].key_snap)
+ game_key_pressed = TRUE;
+ }
+
+ // only handle speed or debug keys if no game key is pressed
+ if (!game_key_pressed)
+ {
+ if (HandleKeysSpeed(key, key_status))
+ return; // do not handle already processed keys again
+
+ if (HandleKeysDebug(key, key_status))
+ return; // do not handle already processed keys again
+ }
// map special keys (media keys / remote control buttons) to default keys
if (key == KSYM_PlayPause)
{
-1, -1,
TYPE_INTEGER, CONF_VALUE_16_BIT(6),
- &li.bd_cycle_delay_ms, 200
+ &li.bd_cycle_delay_ms, 160
},
{
-1, -1,
char *getLocalLevelTemplateFilename(void)
{
- return getDefaultLevelFilename(-1);
+ return getLevelFilenameFromBasename(LEVELTEMPLATE_FILENAME);
}
char *getGlobalLevelTemplateFilename(void)
{
- // global variable "leveldir_current" must be modified in the loop below
- LevelDirTree *leveldir_current_last = leveldir_current;
- char *filename = NULL;
-
- // check for template level in path from current to topmost tree node
-
- while (leveldir_current != NULL)
- {
- filename = getDefaultLevelFilename(-1);
-
- if (fileExists(filename))
- break;
-
- leveldir_current = leveldir_current->node_parent;
- }
-
- // restore global variable "leveldir_current" modified in above loop
- leveldir_current = leveldir_current_last;
-
- return filename;
+ return getFilenameFromCurrentLevelDirUpward(LEVELTEMPLATE_FILENAME);
}
static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
SetDefaultLevelColors_BD();
// level name
- char *cave_name = getStringPrint("%s / %d", cave->name, bd_level_nr + 1);
+ char *cave_name_latin1 = getLatin1FromUTF8(cave->name);
+ char *cave_name_final = (gd_caveset_has_levels() ?
+ getStringPrint("%s / %d", cave_name_latin1, bd_level_nr + 1) :
+ getStringCopy(cave_name_latin1));
- strncpy(level->name, cave_name, MAX_LEVEL_NAME_LEN);
+ strncpy(level->name, cave_name_final, MAX_LEVEL_NAME_LEN);
level->name[MAX_LEVEL_NAME_LEN] = '\0';
// playfield elements
for (y = 0; y < level->fieldy; y++)
level->field[x][y] = CAVE_TO_LEVEL(cave->map[y][x]);
- checked_free(cave_name);
+ checked_free(cave_name_latin1);
+ checked_free(cave_name_final);
}
static void setTapeInfoToDefaults(void);
LoadLevelFromFileInfo(level, &level_file_info, FALSE);
}
+static void LoadLevel_FixEnvelopes(struct LevelInfo *level, boolean skip_single_lines)
+{
+ // This function removes newlines in envelopes after lines of text ending in the last column
+ // of the envelope. In earlier versions, these newlines were removed when displaying envelopes,
+ // but caused trouble in the level editor. In version 4.3.2.3, this problem was partially
+ // fixed in the level editor (but only for single full-width text lines followed by a newline,
+ // not for multiple lines ending in the last column, followed by a newline), but now produced
+ // unwanted newlines in the game for envelopes stored by previous game versions, which was not
+ // intended by the level author (and sometimes caused text lines not being displayed anymore at
+ // the bottom of the envelope).
+ //
+ // This function should solve these problems by removing such newline characters from envelopes
+ // stored by older game versions.
+
+ int envelope_nr;
+
+ for (envelope_nr = 0; envelope_nr < NUM_ENVELOPES; envelope_nr++)
+ {
+ char *envelope_ptr = level->envelope[envelope_nr].text;
+ int envelope_xsize = level->envelope[envelope_nr].xsize;
+ int envelope_size = strlen(envelope_ptr);
+ int start = 0;
+ int i;
+
+ for (i = 0; i < envelope_size; i++)
+ {
+ // check for newlines in envelope
+ if (envelope_ptr[i] == '\n')
+ {
+ int line_length = i - start;
+
+ // check for (non-empty) lines that are a multiple of the envelope width,
+ // causing a line break inside the envelope (text area in editor and in game)
+ if (line_length > 0 && line_length % envelope_xsize == 0)
+ {
+ // special case: skip fixing single lines for newer versions
+ boolean skip_fixing_line = (line_length == 1 && skip_single_lines);
+
+ if (!skip_fixing_line)
+ {
+ int j;
+
+ // remove newline character from string
+ for (j = i; j < envelope_size; j++)
+ envelope_ptr[j] = envelope_ptr[j + 1];
+ }
+
+ // continue with next line (that was copied over the newline)
+ start = i;
+ }
+ else
+ {
+ // continue with next character after newline
+ start = i + 1;
+ }
+ }
+ }
+ }
+}
+
static void LoadLevel_InitVersion(struct LevelInfo *level)
{
int i, j;
// CE changing to player was kept under the player if walkable up to 4.2.3.1
if (level->game_version <= VERSION_IDENT(4,2,3,1))
level->keep_walkable_ce = TRUE;
+
+ // envelopes may contain broken or too many line breaks before 4.4.0.0
+ if (level->game_version < VERSION_IDENT(4,4,0,0))
+ LoadLevel_FixEnvelopes(level, (level->game_version >= VERSION_IDENT(4,3,2,3)));
}
static void LoadLevel_InitSettings_SB(struct LevelInfo *level)
},
{
TYPE_SWITCH_3_STATES,
- &setup.bd_skip_falling_sounds, "bd_skip_falling_sounds"
+ &setup.bd_falling_sounds, "bd_falling_sounds"
},
{
TYPE_INTEGER,
TYPE_SWITCH,
&setup.editor.show_element_token, "editor.show_element_token"
},
+ {
+ TYPE_SWITCH,
+ &setup.editor.fast_game_start, "editor.fast_game_start"
+ },
{
TYPE_SWITCH,
&setup.editor.show_read_only_warning, "editor.show_read_only_warning"
si->bd_smooth_movements = STATE_TRUE;
si->bd_pushing_graphics = STATE_TRUE;
si->bd_up_down_graphics = STATE_TRUE;
- si->bd_skip_falling_sounds = STATE_TRUE;
+ si->bd_falling_sounds = STATE_AUTO;
si->bd_palette_c64 = GD_DEFAULT_PALETTE_C64;
si->bd_palette_c64dtv = GD_DEFAULT_PALETTE_C64DTV;
si->bd_palette_atari = GD_DEFAULT_PALETTE_ATARI;
si->editor.el_headlines = TRUE;
si->editor.show_element_token = FALSE;
+ si->editor.fast_game_start = FALSE;
si->editor.show_read_only_warning = TRUE;
int element = Tile[x][y];
// convert BD engine elements to corresponding R'n'D engine elements
- element = (element == EL_BDX_EMPTY ? EL_EMPTY :
- element == EL_BDX_PLAYER ? EL_PLAYER_1 :
- element == EL_BDX_INBOX ? EL_PLAYER_1 :
- element == EL_BDX_SAND_1 ? EL_SAND :
- element == EL_BDX_STEELWALL ? EL_STEELWALL :
- element == EL_BDX_EXIT_CLOSED ? EL_EXIT_CLOSED :
- element == EL_BDX_EXIT_OPEN ? EL_EXIT_OPEN :
+ element = (element == EL_BDX_EMPTY ? EL_EMPTY :
+ element == EL_BDX_PLAYER ? EL_PLAYER_1 :
+ element == EL_BDX_INBOX ? EL_PLAYER_1 :
+ element == EL_BDX_SAND_1 ? EL_SAND :
+ element == EL_BDX_WALL ? EL_BD_WALL :
+ element == EL_BDX_STEELWALL ? EL_STEELWALL :
+ element == EL_BDX_ROCK ? EL_BD_ROCK :
+ element == EL_BDX_DIAMOND ? EL_BD_DIAMOND :
+ element == EL_BDX_AMOEBA_1 ? EL_BD_AMOEBA :
+ element == EL_BDX_MAGIC_WALL ? EL_BD_MAGIC_WALL :
+ element == EL_BDX_BUTTERFLY_1_RIGHT ? EL_BD_BUTTERFLY_RIGHT :
+ element == EL_BDX_BUTTERFLY_1_UP ? EL_BD_BUTTERFLY_UP :
+ element == EL_BDX_BUTTERFLY_1_LEFT ? EL_BD_BUTTERFLY_LEFT :
+ element == EL_BDX_BUTTERFLY_1_DOWN ? EL_BD_BUTTERFLY_DOWN :
+ element == EL_BDX_BUTTERFLY_1 ? EL_BD_BUTTERFLY :
+ element == EL_BDX_FIREFLY_1_RIGHT ? EL_BD_FIREFLY_RIGHT :
+ element == EL_BDX_FIREFLY_1_UP ? EL_BD_FIREFLY_UP :
+ element == EL_BDX_FIREFLY_1_LEFT ? EL_BD_FIREFLY_LEFT :
+ element == EL_BDX_FIREFLY_1_DOWN ? EL_BD_FIREFLY_DOWN :
+ element == EL_BDX_FIREFLY_1 ? EL_BD_FIREFLY :
+ element == EL_BDX_EXPANDABLE_WALL_HORIZONTAL ? EL_BD_EXPANDABLE_WALL :
+ element == EL_BDX_WALL_DIAMOND ? EL_WALL_BD_DIAMOND :
+ element == EL_BDX_EXIT_CLOSED ? EL_EXIT_CLOSED :
+ element == EL_BDX_EXIT_OPEN ? EL_EXIT_OPEN :
element);
Tile[x][y] = element;
int time = (game.LevelSolved ?
game.LevelSolved_CountingTime :
level.game_engine_type == GAME_ENGINE_TYPE_BD ?
- game_bd.time_played :
+ game_bd.time_left :
level.game_engine_type == GAME_ENGINE_TYPE_EM ?
game_em.lev->time :
level.game_engine_type == GAME_ENGINE_TYPE_SP ?
static void LevelSolved_SetFinalGameValues(void)
{
- game.time_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.time_played :
+ game.time_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.time_left :
game.no_level_time_limit ? TimePlayed : TimeLeft);
- game.score_time_final = (level.use_step_counter ? TimePlayed :
+ game.score_time_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.frames_played :
+ level.use_step_counter ? TimePlayed :
TimePlayed * FRAMES_PER_SECOND + TimeFrames);
game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.score :
// if last second running, wait for native engine time to exactly reach zero
if (getTimeLeft_BD() == 1 && TimeLeft == 1)
TimeFrames = frames_per_second - 1;
+
+ // needed to store final time after solving game (before counting down remaining time)
+ SetTimeFrames_BD(TimePlayed * FRAMES_PER_SECOND + TimeFrames);
}
if (TimeFrames >= frames_per_second)
if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
SaveEngineSnapshotValues_RND();
+ if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+ SaveEngineSnapshotValues_BD();
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
SaveEngineSnapshotValues_EM();
if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd));
+ if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+ SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_bd));
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em));
if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
LoadEngineSnapshotValues_RND();
+ if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+ LoadEngineSnapshotValues_BD();
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
LoadEngineSnapshotValues_EM();
if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
E_P_MOVED_BY_CONVEYOR_TOP, // can be moved by conveyor belt
E_P_MOVED_BY_CONVEYOR_BOTTOM, // can be moved UNDER the conveyor belt
+ E_P_WALKABLE, // can be walked
E_P_DIGGABLE, // can be digged
E_P_COLLECTIBLE, // can be collected
E_P_PUSHABLE, // can be pushed
#define P_MOVED_BY_CONVEYOR_TOP (1 << E_P_MOVED_BY_CONVEYOR_TOP)
#define P_MOVED_BY_CONVEYOR_BOTTOM (1 << E_P_MOVED_BY_CONVEYOR_BOTTOM)
+#define P_WALKABLE (1 << E_P_WALKABLE)
#define P_DIGGABLE (1 << E_P_DIGGABLE)
#define P_COLLECTIBLE (1 << E_P_COLLECTIBLE)
#define P_PUSHABLE (1 << E_P_PUSHABLE)
*/
GdElements gd_elements[] =
{
- { O_SPACE, N_("Space"), P_AMOEBA_CONSUMES, "SPACE", ' ', 0, 0, 0 },
+ { O_SPACE, N_("Space"), P_AMOEBA_CONSUMES | P_WALKABLE, "SPACE", ' ', 0, 0, 0 },
{ O_DIRT, N_("Dirt"), P_AMOEBA_CONSUMES | P_VISUAL_EFFECT | P_DIRT | P_DIGGABLE, "DIRT", '.', 2, 2, 2 },
{ O_DIRT_SLOPED_UP_RIGHT, N_("Sloped dirt (up & right)"), P_DIRT | P_SLOPED_UP | P_SLOPED_RIGHT | P_AMOEBA_CONSUMES | P_DIGGABLE, "DIRTSLOPEDUPRIGHT", 0, 280, 280, 280 },
{ O_DIRT_SLOPED_UP_LEFT, N_("Sloped dirt (up & left)"), P_DIRT | P_SLOPED_UP | P_SLOPED_LEFT | P_AMOEBA_CONSUMES | P_DIGGABLE, "DIRTSLOPEDUPLEFT", 0, 281, 281, 281 },
{ O_POT, N_("Pot"), 0, "POT", 0, 63, 63, 63 },
{ O_GRAVITY_SWITCH, N_("Gravity switch"), 0, "GRAVITY_SWITCH", 0, 274, 274, 274 },
{ O_PNEUMATIC_HAMMER, N_("Pneumatic hammer"), P_COLLECTIBLE, "PNEUMATIC_HAMMER", 0, 62, 62, 62 },
- { O_TELEPORTER, N_("Teleporter"), 0, "TELEPORTER", 0, 61, 61, 61 },
+ { O_TELEPORTER, N_("Teleporter"), P_WALKABLE, "TELEPORTER", 0, 61, 61, 61 },
{ O_SKELETON, N_("Skeleton"), 0, "SKELETON", 0, 273, 273, 273 },
{ O_WATER, N_("Water"), 0, "WATER", 0, 96, -96, -96, 100 }, // has ckdelay
{ O_WATER_1, N_("Water (1)"), 0, "WATER1", 0, 96, -96, -96 },
static void play_sound_of_element(GdCave *cave, GdElement element, int x, int y)
{
// check if sound should be skipped for falling elements (and only be played on impact)
- if (el_can_fall(element) && skip_bd_falling_sounds())
+ if (el_can_fall(element) && !use_bd_falling_sounds())
return;
// stone and diamond fall sounds.
static inline void store_dir_buffer(GdCave *cave, const int x, const int y, const GdDirection dir)
{
+ int old_x = x;
+ int old_y = y;
+
// raw values without range correction
int raw_x = x + gd_dx[dir];
int raw_y = y + gd_dy[dir];
int new_y = gety(cave, raw_x, raw_y);
int new_dir = (dir > GD_MV_TWICE ? dir - GD_MV_TWICE : dir);
- game_bd.game->dir_buffer[new_y][new_x] = new_dir;
+ // if tile is moving two steps at once, correct old position
+ if (dir > GD_MV_TWICE)
+ {
+ raw_x = x + gd_dx[new_dir];
+ raw_y = y + gd_dy[new_dir];
+
+ old_x = getx(cave, raw_x, raw_y);
+ old_y = gety(cave, raw_x, raw_y);
+ }
+
+ game_bd.game->dir_buffer_from[old_y][old_x] = new_dir;
+ game_bd.game->dir_buffer_to[new_y][new_x] = new_dir;
}
// store an element at the given position
gd_cave_clear_sounds(cave);
+ game_bd.player_moving = FALSE;
+ game_bd.player_snapping = FALSE;
+
// if diagonal movements not allowed,
// horizontal movements have precedence. [BROADRIBB]
if (!cave->diagonal_movements)
// if snapping anything and we have snapping explosions set.
// but these is not true for pushing.
if (remains == O_SPACE && player_fire && !push)
+ {
remains = cave->snap_element;
+ game_bd.player_snapping = TRUE;
+ }
+
if (remains != O_SPACE || player_fire)
+ {
// if any other element than space, player cannot move.
// also if pressing fire, will not move.
store_dir(cave, x, y, player_move, remains);
+ }
else
+ {
// if space remains there, the player moves.
move(cave, x, y, player_move, O_PLAYER);
+
+ game_bd.player_moving = TRUE;
+ }
}
}
break;
SCANNED = 0x100,
COVERED = 0x200,
- SKIPPED = 0x400,
// binary AND this to elements to get rid of properties above.
- O_MASK = ~(SCANNED | COVERED | SKIPPED)
+ O_MASK = ~(SCANNED | COVERED)
} GdElement;
typedef enum _sound
gd_cave_map_free(game->element_buffer);
if (game->last_element_buffer)
gd_cave_map_free(game->last_element_buffer);
- if (game->dir_buffer)
- gd_cave_map_free(game->dir_buffer);
+ if (game->dir_buffer_from)
+ gd_cave_map_free(game->dir_buffer_from);
+ if (game->dir_buffer_to)
+ gd_cave_map_free(game->dir_buffer_to);
if (game->gfx_buffer)
gd_cave_map_free(game->gfx_buffer);
gd_cave_map_free(game->last_element_buffer);
game->last_element_buffer = NULL;
- // delete direction buffer
- if (game->dir_buffer)
- gd_cave_map_free(game->dir_buffer);
- game->dir_buffer = NULL;
+ // delete direction buffer (from)
+ if (game->dir_buffer_from)
+ gd_cave_map_free(game->dir_buffer_from);
+ game->dir_buffer_from = NULL;
+
+ // delete direction buffer (to)
+ if (game->dir_buffer_to)
+ gd_cave_map_free(game->dir_buffer_to);
+ game->dir_buffer_to = NULL;
// delete gfx buffer
if (game->gfx_buffer)
game->milliseconds_anim = 0;
game->milliseconds_game = 0; // set game timer to zero, too
+ game->cycle_counter = 0;
+
// create new element buffer
game->element_buffer = gd_cave_map_new(game->cave, int);
for (x = 0; x < game->cave->w; x++)
game->last_element_buffer[y][x] = O_NONE;
- // create new direction buffer
- game->dir_buffer = gd_cave_map_new(game->cave, int);
+ // create new direction buffer (from)
+ game->dir_buffer_from = gd_cave_map_new(game->cave, int);
for (y = 0; y < game->cave->h; y++)
for (x = 0; x < game->cave->w; x++)
- game->dir_buffer[y][x] = GD_MV_STILL;
+ game->dir_buffer_from[y][x] = GD_MV_STILL;
+
+ // create new direction buffer (to)
+ game->dir_buffer_to = gd_cave_map_new(game->cave, int);
+
+ for (y = 0; y < game->cave->h; y++)
+ for (x = 0; x < game->cave->w; x++)
+ game->dir_buffer_to[y][x] = GD_MV_STILL;
// create new gfx buffer
game->gfx_buffer = gd_cave_map_new(game->cave, int);
return game;
}
+boolean check_iteration_reached(GdGame *game)
+{
+ int millisecs_elapsed = 20;
+
+ return (game->milliseconds_game + millisecs_elapsed >= game->cave->speed);
+}
+
static void iterate_cave(GdGame *game, GdDirection player_move, boolean fire)
{
boolean suicide = FALSE;
{
for (x = 0; x < game->cave->w; x++)
{
- game->last_element_buffer[y][x] = game->element_buffer[y][x] & ~SKIPPED;
- game->dir_buffer[y][x] = GD_MV_STILL;
+ game->last_element_buffer[y][x] = game->element_buffer[y][x];
+ game->dir_buffer_from[y][x] = GD_MV_STILL;
+ game->dir_buffer_to[y][x] = GD_MV_STILL;
}
}
- // store last maximum number of cycles (to force redraw if changed)
+ // store last maximum number of cycle frames (to force redraw if changed)
game->itermax_last = game->itermax;
- // update maximum number of cycles (frame) per cave iteration
- game->itermax = game->itercycle;
+ // store maximum number of cycle frames separately for even and odd cycles
+ game->itermax2[game->cycle_counter % 2] = game->itercycle;
+
+ // update maximum number of cycle frames per cave iteration
+ game->itermax = game->itermax2[!(game->cycle_counter % 2)];
- // reset cycle (frame) counter for the next cave iteration
+ // reset cycle frame counter for the next cave iteration
game->itercycle = 0;
iterate_cave(game, game->player_move, game->player_fire);
+ game->cycle_counter++;
+
if (game->player_move == GD_MV_STILL)
{
game->player_move_stick = FALSE;
int state_counter; // counter used to control the game flow, rendering of caves
int **element_buffer;
int **last_element_buffer;
- int **dir_buffer;
+ int **dir_buffer_from;
+ int **dir_buffer_to;
int **gfx_buffer; // contains the indexes to the cells;
// created by *start_level, deleted by *stop_game
int itercycle;
int itermax;
int itermax_last;
+ int itermax2[2];
int animcycle;
int milliseconds_game;
int milliseconds_anim;
+ int cycle_counter;
int replay_no_more_movements;
boolean show_story; // to remember that story for a particular cave was already shown.
GdGame *gd_game_new_snapshot(GdCave *snapshot);
GdGame *gd_game_new_test(GdCave *cave, int level);
+boolean check_iteration_reached(GdGame *game);
+
void play_game_func(GdGame *game, int action);
#endif // BD_GAMEPLAY_H
return has_c64_colors;
}
+boolean gd_bitmap_has_c64_colors(Bitmap *bitmap)
+{
+ return surface_has_c64_colors(bitmap->surface);
+}
+
// sets one of the colors in the indexed palette of an sdl surface to a GdColor.
static void set_surface_palette_color(SDL_Surface *surface, int index, GdColor col)
{
set_surface_palette_color(surface, 7, 0);
set_surface_palette_color(surface, 8, 0);
+ // set background color to be transparent for masked tile bitmap
+ int bg_color = gd_color_get_rgb(cave->color0);
+ int bg_r = gd_color_get_r(bg_color);
+ int bg_g = gd_color_get_g(bg_color);
+ int bg_b = gd_color_get_b(bg_color);
+
// create bitmap from C64 surface
- tile_bitmap_c64 = SDLGetBitmapFromSurface(surface);
+ tile_bitmap_c64 = SDLGetBitmapFromSurface_WithMaskedColor(surface, bg_r, bg_g, bg_b);
return tile_bitmap_c64;
}
return (gd_elements[element & O_MASK].properties & P_PLAYER) != 0;
}
+// returns true if the element is walkable
+static inline boolean el_walkable(const int element)
+{
+ return (gd_elements[element & O_MASK].properties & P_WALKABLE) != 0;
+}
+
// returns true if the element is diggable
static inline boolean el_diggable(const int element)
{
{
return (gd_elements[element & O_MASK].properties & P_COLLECTIBLE) != 0;
}
-#endif
// returns true if the element is pushable
static inline boolean el_pushable(const int element)
{
return (gd_elements[element & O_MASK].properties & P_FALLING) != 0;
}
+#endif
// returns true if the element is growing
static inline boolean el_growing(const int element)
GdCave *cave = game->cave;
int sx = x * cell_size - scroll_x;
int sy = y * cell_size - scroll_y;
- int dir = game->dir_buffer[y][x];
+ int dir_from = game->dir_buffer_from[y][x];
+ int dir_to = game->dir_buffer_to[y][x];
int tile = game->element_buffer[y][x];
+ int tile_last = game->last_element_buffer[y][x];
+ int tile_from = O_NONE; // source element if element is moving (will be set later)
+ int tile_to = tile; // target element if element is moving
int frame = game->animcycle;
- struct GraphicInfo_BD *g = &graphic_info_bd_object[tile][frame];
- Bitmap *tile_bitmap = gd_get_tile_bitmap(g->bitmap);
- boolean is_movable = (el_can_move(tile) || el_falling(tile) || el_pushable(tile) ||
- el_player(tile));
- boolean is_movable_or_diggable = (is_movable || el_diggable(game->last_element_buffer[y][x]));
- boolean is_moving = (is_movable_or_diggable && dir != GD_MV_STILL);
+ boolean is_moving_from = (dir_from != GD_MV_STILL);
+ boolean is_moving_to = (dir_to != GD_MV_STILL);
+ boolean is_moving = (is_moving_from || is_moving_to);
boolean use_smooth_movements = use_bd_smooth_movements();
- // do not use smooth movement animation for growing or exploding game elements
- if ((el_growing(tile) || el_explosion(tile)) && dir != GD_MV_STILL)
+ // if element is moving away from this tile, determine element that is moving
+ if (is_moving_from)
{
- int dx = (dir == GD_MV_LEFT ? +1 : dir == GD_MV_RIGHT ? -1 : 0);
- int dy = (dir == GD_MV_UP ? +1 : dir == GD_MV_DOWN ? -1 : 0);
- int old_x = cave->getx(cave, x + dx, y + dy);
- int old_y = cave->gety(cave, x + dx, y + dy);
- int last_tile_from = game->last_element_buffer[old_y][old_x] & ~SKIPPED;
- boolean old_is_player = el_player(last_tile_from);
-
- // check special case of player running into enemy from top or left side
- if (old_is_player)
- {
- game->element_buffer[y][x] = (dir == GD_MV_LEFT ? O_PLAYER_LEFT :
- dir == GD_MV_RIGHT ? O_PLAYER_RIGHT :
- dir == GD_MV_UP ? O_PLAYER_UP :
- dir == GD_MV_DOWN ? O_PLAYER_DOWN : O_PLAYER);
-
- // draw player running into explosion (else player would disappear immediately)
- gd_drawcave_tile(dest, game, x, y, draw_masked);
+ int dx = (dir_from == GD_MV_LEFT ? -1 : dir_from == GD_MV_RIGHT ? +1 : 0);
+ int dy = (dir_from == GD_MV_UP ? -1 : dir_from == GD_MV_DOWN ? +1 : 0);
+ int new_x = cave->getx(cave, x + dx, y + dy);
+ int new_y = cave->gety(cave, x + dx, y + dy);
- game->element_buffer[y][x] = tile;
- }
+ tile_from = game->element_buffer[new_y][new_x];
- use_smooth_movements = FALSE;
+ // handle special case of player running into enemy/explosion from top or left side
+ if ((el_growing(tile_from) || el_explosion(tile_from)) && el_player(tile_last))
+ tile_from = tile_last;
}
+ // --------------------------------------------------------------------------------
+ // check if we should use smooth movement animations or not
+ // --------------------------------------------------------------------------------
+
// do not use smooth movement animation for player entering exit (engine stopped)
if (cave->player_state == GD_PL_EXITED)
use_smooth_movements = FALSE;
+ // never treat empty space as "moving" (source tile if player is snapping)
+ if (tile_from == O_SPACE)
+ use_smooth_movements = FALSE;
+
+ // do not use smooth movement animation for player stirring the pot
+ if (tile_from == O_PLAYER_STIRRING || tile_to == O_PLAYER_STIRRING)
+ use_smooth_movements = FALSE;
+
+ // do not use smooth movement animation for growing or exploding game elements
+ if (el_growing(tile) || el_explosion(tile))
+ use_smooth_movements = FALSE;
+
#if DO_GFX_SANITY_CHECK
if (use_native_bd_graphics_engine() && !setup.small_game_graphics && !program.headless)
{
+ struct GraphicInfo_BD *g = &graphic_info_bd_object[tile][frame];
int old_x = (game->gfx_buffer[y][x] % GD_NUM_OF_CELLS) % GD_NUM_OF_CELLS_X;
int old_y = (game->gfx_buffer[y][x] % GD_NUM_OF_CELLS) / GD_NUM_OF_CELLS_X;
int new_x = g->src_x / g->width;
// if game element not moving (or no smooth movements requested), simply draw tile
if (!is_moving || !use_smooth_movements)
{
+ struct GraphicInfo_BD *g = &graphic_info_bd_object[tile][frame];
+ Bitmap *tile_bitmap = gd_get_tile_bitmap(g->bitmap);
+
blit_bitmap(tile_bitmap, dest, g->src_x, g->src_y, cell_size, cell_size, sx, sy);
return;
}
+ // --------------------------------------------------------------------------------
// draw smooth animation for game element moving between two cave tiles
+ // --------------------------------------------------------------------------------
- if (!(game->last_element_buffer[y][x] & SKIPPED))
- {
- // redraw previous game element on the cave field the new element is moving to
- int tile_last = game->last_element_buffer[y][x];
-
- // only redraw previous game element if it is diggable (like dirt etc.)
- if (!el_diggable(tile_last))
- tile_last = O_SPACE;
-
- struct GraphicInfo_BD *g_old = &graphic_info_bd_object[tile_last][frame];
- Bitmap *tile_bitmap_old = gd_get_tile_bitmap(g_old->bitmap);
-
- blit_bitmap(tile_bitmap_old, dest, g_old->src_x, g_old->src_y, cell_size, cell_size, sx, sy);
- }
-
- // get cave field position the game element is moving from
- int dx = (dir == GD_MV_LEFT ? +1 : dir == GD_MV_RIGHT ? -1 : 0);
- int dy = (dir == GD_MV_UP ? +1 : dir == GD_MV_DOWN ? -1 : 0);
- int old_x = cave->getx(cave, x + dx, y + dy);
- int old_y = cave->gety(cave, x + dx, y + dy);
- int tile_from = game->element_buffer[old_y][old_x] & ~SKIPPED; // should never be skipped
- struct GraphicInfo_BD *g_from = &graphic_info_bd_object[tile_from][frame];
- Bitmap *tile_bitmap_from = gd_get_tile_bitmap(g_from->bitmap);
- boolean old_is_player = el_player(tile_from);
- boolean old_is_moving = (game->dir_buffer[old_y][old_x] != GD_MV_STILL);
- boolean old_is_visible = (old_x >= cave->x1 &&
- old_x <= cave->x2 &&
- old_y >= cave->y1 &&
- old_y <= cave->y2);
- if (old_is_visible)
+ // ---------- 1st step: draw background element for this tile ----------
{
- if (!old_is_moving && !old_is_player)
- {
- // redraw game element on the cave field the element is moving from
- blit_bitmap(tile_bitmap_from, dest, g_from->src_x, g_from->src_y, cell_size, cell_size,
- sx + dx * cell_size, sy + dy * cell_size);
+ int tile_back = (!is_moving_to ? tile : el_diggable(tile_last) ? tile_last : O_SPACE);
+ struct GraphicInfo_BD *g = &graphic_info_bd_object[tile_back][frame];
+ Bitmap *tile_bitmap = gd_get_tile_bitmap(g->bitmap);
- game->element_buffer[old_y][old_x] |= SKIPPED;
- }
- else
- {
- // if old tile also moving (like pushing player), do not redraw tile background
- // (but redraw if tile and old tile are moving/falling into different directions)
- if (game->dir_buffer[old_y][old_x] == game->dir_buffer[y][x])
- game->last_element_buffer[old_y][old_x] |= SKIPPED;
- }
+ blit_bitmap(tile_bitmap, dest, g->src_x, g->src_y, cell_size, cell_size, sx, sy);
}
// get shifted position between cave fields the game element is moving from/to
int itercycle = MIN(MAX(0, game->itermax - game->itercycle - 1), game->itermax);
int shift = cell_size * itercycle / game->itermax;
- blit_bitmap(tile_bitmap, dest, g->src_x, g->src_y, cell_size, cell_size,
- sx + dx * shift, sy + dy * shift);
+ // ---------- 2nd step: draw element that is moving away from this tile ----------
- // special case: redraw player snapping a game element
- if (old_is_visible && old_is_player && !old_is_moving)
+ if (is_moving_from)
{
- // redraw game element on the cave field the element is moving from
- blit_bitmap(tile_bitmap_from, dest, g_from->src_x, g_from->src_y, cell_size, cell_size,
- sx + dx * cell_size, sy + dy * cell_size);
+ struct GraphicInfo_BD *g = &graphic_info_bd_object[tile_from][frame];
+ Bitmap *tile_bitmap = gd_get_tile_bitmap(g->bitmap);
+ int dx = (dir_from == GD_MV_LEFT ? -1 : dir_from == GD_MV_RIGHT ? +1 : 0);
+ int dy = (dir_from == GD_MV_UP ? -1 : dir_from == GD_MV_DOWN ? +1 : 0);
+ int xsize = (dx != 0 ? shift : cell_size);
+ int ysize = (dy != 0 ? shift : cell_size);
+ int gx = g->src_x + (dx < 0 ? cell_size - shift : 0);
+ int gy = g->src_y + (dy < 0 ? cell_size - shift : 0);
+ int tx = sx + (dx < 0 ? 0 : dx > 0 ? cell_size - shift : 0);
+ int ty = sy + (dy < 0 ? 0 : dy > 0 ? cell_size - shift : 0);
+
+ if (el_walkable(tile))
+ blit_bitmap = BlitBitmapMasked;
+
+ blit_bitmap(tile_bitmap, dest, gx, gy, xsize, ysize, tx, ty);
+
+ // when using dynamic scheduling (mainly BD1 levels), redraw tile in next frame
+ game->gfx_buffer[y][x] |= GD_REDRAW;
+ }
+
+ // ---------- 3rd step: draw element that is moving towards this tile ----------
+
+ if (is_moving_to)
+ {
+ struct GraphicInfo_BD *g = &graphic_info_bd_object[tile_to][frame];
+ Bitmap *tile_bitmap = gd_get_tile_bitmap(g->bitmap);
+ int dx = (dir_to == GD_MV_LEFT ? +1 : dir_to == GD_MV_RIGHT ? -1 : 0);
+ int dy = (dir_to == GD_MV_UP ? +1 : dir_to == GD_MV_DOWN ? -1 : 0);
+ int xsize = (dx != 0 ? cell_size - shift : cell_size);
+ int ysize = (dy != 0 ? cell_size - shift : cell_size);
+ int gx = g->src_x + (dx < 0 ? shift : 0);
+ int gy = g->src_y + (dy < 0 ? shift : 0);
+ int tx = sx + (dx < 0 ? 0 : dx > 0 ? shift : 0);
+ int ty = sy + (dy < 0 ? 0 : dy > 0 ? shift : 0);
+
+ if (is_moving_from)
+ blit_bitmap = BlitBitmapMasked;
+
+ blit_bitmap(tile_bitmap, dest, gx, gy, xsize, ysize, tx, ty);
+
+ // when using dynamic scheduling (mainly BD1 levels), redraw tile in next frame
+ game->gfx_buffer[y][x] |= GD_REDRAW;
}
}
{
if (redraw_all ||
game->gfx_buffer[y][x] & GD_REDRAW ||
- game->dir_buffer[y][x] != GD_MV_STILL)
+ game->dir_buffer_from[y][x] != GD_MV_STILL ||
+ game->dir_buffer_to[y][x] != GD_MV_STILL)
{
- // skip redrawing already drawn element with movement
- if (game->element_buffer[y][x] & SKIPPED)
- continue;
-
// now we have drawn it
game->gfx_buffer[y][x] = game->gfx_buffer[y][x] & ~GD_REDRAW;
void gd_init_play_area(void);
+boolean gd_bitmap_has_c64_colors(Bitmap *bitmap);
void gd_prepare_tile_bitmap(GdCave *cave, Bitmap *bitmap, int scale_down_factor);
void gd_set_tile_bitmap_reference(Bitmap *bitmap);
Bitmap *gd_get_tile_bitmap(Bitmap *bitmap);
boolean game_over;
boolean cover_screen;
+ boolean player_moving;
+ boolean player_snapping;
+
// needed for updating panel
- int time_played;
+ int time_left;
int gems_still_needed;
int score;
+
+ // needed for saving score time
+ int frames_played;
};
struct LevelInfo_BD
struct EngineSnapshotInfo_BD
{
+ GdGame game;
+
+ // data from pointers in game structure
+ int element_buffer[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+ int last_element_buffer[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+ int dir_buffer_from[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+ int dir_buffer_to[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+ int gfx_buffer[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+
+ GdCave cave;
+
+ // data from pointers in cave structure
+ short map[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+ short hammered_reappear[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
};
boolean checkBonusTime_BD(void);
int getFramesPerSecond_BD(void);
int getTimeLeft_BD(void);
+void SetTimeFrames_BD(int);
void InitGfxBuffers_BD(void);
boolean use_bd_smooth_movements(void);
boolean use_bd_pushing_graphics(void);
boolean use_bd_up_down_graphics(void);
-boolean skip_bd_falling_sounds(void);
+boolean use_bd_falling_sounds(void);
+
+boolean hasColorTemplate_BD(void);
Bitmap **GetTitleScreenBitmaps_BD(void);
void CoverScreen_BD(void);
void BlitScreenToBitmap_BD(Bitmap *);
void RedrawPlayfield_BD(boolean);
+void SaveEngineSnapshotValues_BD(void);
+void LoadEngineSnapshotValues_BD(void);
+
#endif // EXPORT_BD_H
// ----------------------------------------------------------------------------
void InitGraphicInfo_BD(void);
+boolean CheckSingleStepMode_BD(boolean, boolean, boolean);
void PlayLevelSound_BD(int, int, int, int);
void StopSound_BD(int, int);
byte *TapeCorrectAction_BD(byte *);
boolean TapeIsPlaying_ReplayBD(void);
-boolean isLevelEditorTestGame(void);
+boolean isLevelEditorFastStart(void);
#endif // IMPORT_BD_H
return 0;
}
+void SetTimeFrames_BD(int frames_played)
+{
+ // needed to store final time after solving game (before counting down remaining time)
+ if (game_bd.game->state_counter == GAME_INT_CAVE_RUNNING)
+ game_bd.frames_played = frames_played;
+
+}
+
static void UpdateGameDoorValues_BD(void)
{
GdCave *cave = game_bd.game->cave;
- int time_secs = gd_cave_time_show(cave, cave->time);
+ int time_left = gd_cave_time_show(cave, cave->time);
int gems_still_needed = MAX(0, (cave->diamonds_needed - cave->diamonds_collected));
- game_bd.time_played = time_secs;
+ game_bd.time_left = time_left;
game_bd.gems_still_needed = gems_still_needed;
game_bd.score = game_bd.game->player_score;
if (game.LevelSolved)
{
// update time and score in panel while counting bonus time
- game.LevelSolved_CountingTime = game_bd.time_played;
+ game.LevelSolved_CountingTime = game_bd.time_left;
game.LevelSolved_CountingScore = game_bd.score;
}
}
game_bd.game_over = FALSE;
game_bd.cover_screen = FALSE;
- game_bd.time_played = 0;
- game_bd.gems_still_needed = 0;
- game_bd.score = 0;
-
gd_caveset_last_selected = native_bd_level.cave_nr;
gd_caveset_last_selected_level = native_bd_level.level_nr;
game_bd.game->itercycle = 0;
game_bd.game->itermax = 8; // default; dynamically changed at runtime
game_bd.game->itermax_last = game_bd.game->itermax;
+ game_bd.game->itermax2[0] = game_bd.game->itermax;
+ game_bd.game->itermax2[1] = game_bd.game->itermax;
+
+ game_bd.player_moving = FALSE;
+ game_bd.player_snapping = FALSE;
// default: start with completely covered playfield
int next_state = GAME_INT_START_UNCOVER + 1;
// when skipping uncovering, continue with uncovered playfield
if (setup.bd_skip_uncovering)
game_bd.game->state_counter = GAME_INT_UNCOVER_ALL + 1;
- else if (isLevelEditorTestGame())
+ else if (isLevelEditorFastStart())
game_bd.game->state_counter = GAME_INT_UNCOVER_ALL - 8;
- if (setup.bd_skip_uncovering || isLevelEditorTestGame())
+ if (setup.bd_skip_uncovering || isLevelEditorFastStart())
gd_scroll(game_bd.game, TRUE, TRUE);
ClearRectangle(gd_screen_bitmap, 0, 0, SXSIZE, SYSIZE);
play_game_func(game_bd.game, action[0]);
}
+ boolean single_step_mode_paused =
+ CheckSingleStepMode_BD(check_iteration_reached(game_bd.game),
+ game_bd.player_moving,
+ game_bd.player_snapping);
+
+ // draw final movement animation frame before going to single step pause mode
+ if (single_step_mode_paused)
+ game_bd.game->itercycle = game_bd.game->itermax - 1;
+
RedrawPlayfield_BD(FALSE);
UpdateGameDoorValues_BD();
(setup.bd_up_down_graphics == STATE_AUTO && !use_native_bd_graphics_engine()));
}
-// check if skipping falling sounds selected in setup menu
-boolean skip_bd_falling_sounds(void)
+// check if element falling sounds selected in setup menu
+boolean use_bd_falling_sounds(void)
+{
+ return ((setup.bd_falling_sounds == STATE_TRUE) ||
+ (setup.bd_falling_sounds == STATE_AUTO && game.use_native_bd_sound_engine));
+}
+
+boolean hasColorTemplate_BD(void)
{
- return ((setup.bd_skip_falling_sounds == STATE_TRUE) ||
- (setup.bd_skip_falling_sounds == STATE_AUTO && !game.use_native_bd_sound_engine));
+ return gd_bitmap_has_c64_colors(graphic_info_bd_color_template.bitmap);
}
Bitmap **GetTitleScreenBitmaps_BD(void)
{
gd_drawcave(gd_screen_bitmap, game_bd.game, force_redraw);
}
+
+
+// ============================================================================
+// snapshot functions
+// ============================================================================
+
+void SaveEngineSnapshotValues_BD(void)
+{
+ GdGame *game = game_bd.game;
+ GdCave *cave = game_bd.game->cave;
+ int x, y;
+
+ engine_snapshot_bd.game = *game;
+
+ for (y = 0; y < cave->h; y++)
+ {
+ for (x = 0; x < cave->w; x++)
+ {
+ engine_snapshot_bd.element_buffer[x][y] = game->element_buffer[y][x];
+ engine_snapshot_bd.last_element_buffer[x][y] = game->last_element_buffer[y][x];
+ engine_snapshot_bd.dir_buffer_from[x][y] = game->dir_buffer_from[y][x];
+ engine_snapshot_bd.dir_buffer_to[x][y] = game->dir_buffer_to[y][x];
+ engine_snapshot_bd.gfx_buffer[x][y] = game->gfx_buffer[y][x];
+ }
+ }
+
+ engine_snapshot_bd.cave = *cave;
+
+ for (y = 0; y < cave->h; y++)
+ {
+ for (x = 0; x < cave->w; x++)
+ {
+ engine_snapshot_bd.map[x][y] = cave->map[y][x];
+
+ if (cave->hammered_walls_reappear)
+ engine_snapshot_bd.hammered_reappear[x][y] = cave->hammered_reappear[y][x];
+ }
+ }
+}
+
+void LoadEngineSnapshotValues_BD(void)
+{
+ GdGame *game = game_bd.game;
+ GdCave *cave = game_bd.game->cave;
+ int x, y;
+
+ // copy pointers
+ engine_snapshot_bd.game.cave = game->cave;
+ engine_snapshot_bd.game.original_cave = game->original_cave;
+
+ engine_snapshot_bd.game.element_buffer = game->element_buffer;
+ engine_snapshot_bd.game.last_element_buffer = game->last_element_buffer;
+ engine_snapshot_bd.game.dir_buffer_from = game->dir_buffer_from;
+ engine_snapshot_bd.game.dir_buffer_to = game->dir_buffer_to;
+ engine_snapshot_bd.game.gfx_buffer = game->gfx_buffer;
+
+ *game = engine_snapshot_bd.game;
+
+ for (y = 0; y < cave->h; y++)
+ {
+ for (x = 0; x < cave->w; x++)
+ {
+ game->element_buffer[y][x] = engine_snapshot_bd.element_buffer[x][y];
+ game->last_element_buffer[y][x] = engine_snapshot_bd.last_element_buffer[x][y];
+ game->dir_buffer_from[y][x] = engine_snapshot_bd.dir_buffer_from[x][y];
+ game->dir_buffer_to[y][x] = engine_snapshot_bd.dir_buffer_to[x][y];
+ game->gfx_buffer[y][x] = engine_snapshot_bd.gfx_buffer[x][y];
+ }
+ }
+
+ // copy pointers
+ engine_snapshot_bd.cave.story = cave->story;
+ engine_snapshot_bd.cave.remark = cave->remark;
+ engine_snapshot_bd.cave.tags = cave->tags;
+ engine_snapshot_bd.cave.map = cave->map;
+ engine_snapshot_bd.cave.objects = cave->objects;
+ engine_snapshot_bd.cave.replays = cave->replays;
+ engine_snapshot_bd.cave.random = cave->random;
+ engine_snapshot_bd.cave.objects_order = cave->objects_order;
+ engine_snapshot_bd.cave.hammered_reappear = cave->hammered_reappear;
+
+ *cave = engine_snapshot_bd.cave;
+
+ for (y = 0; y < cave->h; y++)
+ {
+ for (x = 0; x < cave->w; x++)
+ {
+ cave->map[y][x] = engine_snapshot_bd.map[x][y];
+
+ if (cave->hammered_walls_reappear)
+ cave->hammered_reappear[y][x] = engine_snapshot_bd.hammered_reappear[x][y];
+ }
+ }
+
+ gd_scroll(game_bd.game, TRUE, TRUE);
+}
DrawMainMenu();
+ if (options.drop_file != NULL)
+ PushDropEvent(options.drop_file);
+
#if 0
Debug("internal:path", "SDL_GetBasePath() == '%s'",
SDL_GetBasePath());
options.player_name = NULL;
options.identifier = NULL;
options.level_nr = NULL;
+ options.drop_file = NULL;
options.display_nr = 0;
if (option_arg == next_option)
options_left++;
}
+ else if (strncmp(option, "-drop-file", option_len) == 0)
+ {
+ if (option_arg == NULL)
+ FailWithHelp("option '%s' requires an argument", option_str);
+
+ options.drop_file = getStringCopy(option_arg);
+ if (option_arg == next_option)
+ options_left++;
+ }
else if (strncmp(option, "-verbose", option_len) == 0)
{
options.verbose = TRUE;
return surface;
}
-Bitmap *SDLGetBitmapFromSurface(SDL_Surface *surface)
+Bitmap *SDLGetBitmapFromSurface_WithMaskedColor(SDL_Surface *surface, int r, int g, int b)
{
int width = surface->w;
int height = surface->h;
if (!SDLHasAlpha(bitmap->surface_masked) &&
!SDLHasColorKey(bitmap->surface_masked))
SDL_SetColorKey(bitmap->surface_masked, SET_TRANSPARENT_PIXEL,
- SDL_MapRGB(bitmap->surface_masked->format, 0x00, 0x00, 0x00));
+ SDL_MapRGB(bitmap->surface_masked->format, r, g, b));
return bitmap;
}
+Bitmap *SDLGetBitmapFromSurface(SDL_Surface *surface)
+{
+ return SDLGetBitmapFromSurface_WithMaskedColor(surface, 0x00, 0x00, 0x00);
+}
+
static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
{
if (program.headless)
boolean SDLSetNativeSurface(SDL_Surface **);
SDL_Surface *SDLGetNativeSurface(SDL_Surface *);
SDL_Surface *SDLCreateNativeSurface(int, int, int);
+Bitmap *SDLGetBitmapFromSurface_WithMaskedColor(SDL_Surface *, int, int, int);
Bitmap *SDLGetBitmapFromSurface(SDL_Surface *);
void SDLCreateBitmapTextures(Bitmap *);
void SDLFreeBitmapTextures(Bitmap *);
return filename;
}
-char *getHelpAnimFilename(void)
+char *getFilenameFromCurrentLevelDirUpward(char *basename)
{
+ // global variable "leveldir_current" must be modified in the loop below
+ LevelDirTree *leveldir_current_last = leveldir_current;
static char *filename = NULL;
- checked_free(filename);
+ // check for filename in path from current to topmost tree node
+
+ while (leveldir_current != NULL)
+ {
+ checked_free(filename);
+
+ filename = getPath2(getCurrentLevelDir(), basename);
+
+ if (fileExists(filename))
+ break;
+
+ leveldir_current = leveldir_current->node_parent;
+ }
- filename = getPath2(getCurrentLevelDir(), HELPANIM_FILENAME);
+ // restore global variable "leveldir_current" modified in above loop
+ leveldir_current = leveldir_current_last;
return filename;
}
-char *getHelpTextFilename(void)
+static char *getHelpFilename(char *basename)
{
static char *filename = NULL;
checked_free(filename);
- filename = getPath2(getCurrentLevelDir(), HELPTEXT_FILENAME);
+ // 1st try: look for help filename in current level set directory
+ filename = getPath2(getCurrentLevelDir(), basename);
+ if (fileExists(filename))
+ return filename;
- return filename;
+ free(filename);
+
+ // 2nd try: look for help filename in configured graphics set directory
+ filename = getPath2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
+
+ // 3rd try: look for help filename in path from current to topmost level set directory
+ filename = getStringCopy(getFilenameFromCurrentLevelDirUpward(basename));
+ if (fileExists(filename))
+ return filename;
+
+ return NULL;
+}
+
+char *getHelpAnimFilename(void)
+{
+ return getHelpFilename(HELPANIM_FILENAME);
+}
+
+char *getHelpTextFilename(void)
+{
+ return getHelpFilename(HELPTEXT_FILENAME);
}
static char *getLevelSetInfoBasename(int nr)
char *getDefaultSetupFilename(void);
char *getPlatformSetupFilename(void);
char *getEditorSetupFilename(void);
+char *getFilenameFromCurrentLevelDirUpward(char *);
char *getHelpAnimFilename(void);
char *getHelpTextFilename(void);
char *getLevelSetInfoFilename(int);
SDL_PushEvent((SDL_Event *)&event);
}
+void PushDropEvent(char *file)
+{
+ SDL_DropEvent event;
+
+ SDL_memset(&event, 0, sizeof(event));
+
+ event.type = SDL_DROPBEGIN;
+ event.file = NULL;
+
+ SDL_PushEvent((SDL_Event *)&event);
+
+ event.type = SDL_DROPFILE;
+ event.file = getStringCopy(file);
+
+ SDL_PushEvent((SDL_Event *)&event);
+
+ event.type = SDL_DROPCOMPLETE;
+ event.file = NULL;
+
+ SDL_PushEvent((SDL_Event *)&event);
+}
+
boolean PendingEscapeKeyEvent(void)
{
if (PendingEvent())
char *identifier;
char *level_nr;
+ char *drop_file;
+
int display_nr;
boolean mytapes;
boolean el_by_type;
boolean show_element_token;
+ boolean fast_game_start;
boolean show_read_only_warning;
int bd_smooth_movements; // not boolean -- can also be "MODE_AUTO"
int bd_pushing_graphics; // not boolean -- can also be "MODE_AUTO"
int bd_up_down_graphics; // not boolean -- can also be "MODE_AUTO"
- int bd_skip_falling_sounds; // not boolean -- can also be "MODE_AUTO"
+ int bd_falling_sounds; // not boolean -- can also be "MODE_AUTO"
int bd_palette_c64;
int bd_palette_c64dtv;
int bd_palette_atari;
void StartTextInput(int, int, int, int);
void StopTextInput(void);
void PushUserEvent(int, int, int);
+void PushDropEvent(char *);
boolean PendingEscapeKeyEvent(void);
void InitJoysticks(void);
{
if ((line[i] = *text_buffer++) == '\n')
{
- // in text areas, 'line_length' sized lines cause additional empty line
- if (i == line_length && is_text_area)
+ // in text areas, do not skip newline after text ending at last column
+ if (i > 0 && i % line_length == 0 && is_text_area)
text_buffer--;
break;
if ((filename != NULL) && (mode_fopen != NULL))
{
- file = fopen64((const char*)filename, mode_fopen);
+ const char *fd_prefix = "fd:";
+ if (strncmp(filename, fd_prefix, strlen(fd_prefix)) == 0)
+ file = fdopen(dup(atoi(&((const char*)filename)[strlen(fd_prefix)])), mode_fopen);
+ else
+ file = fopen64((const char*)filename, mode_fopen);
return file_build_ioposix(file, (const char*)filename);
}
return file;
" -g, --graphics DIRECTORY alternative graphics DIRECTORY\n"
" -s, --sounds DIRECTORY alternative sounds DIRECTORY\n"
" -m, --music DIRECTORY alternative music DIRECTORY\n"
+ " --drop-file FILE drop FILE into program window\n"
" --display NR open program window on display NR\n"
" --mytapes use private tapes for tape tests\n"
" -n, --network network multiplayer game\n"
#define IMG_UNDEFINED (-1)
#define IMG_EMPTY IMG_EMPTY_SPACE
-#define IMG_SP_EMPTY IMG_EMPTY_SPACE
-#define IMG_SP_EMPTY_SPACE IMG_EMPTY_SPACE
#define IMG_EXPLOSION IMG_DEFAULT_EXPLODING
#define IMG_CHAR_START IMG_CHAR_SPACE
#define IMG_STEEL_CHAR_START IMG_STEEL_CHAR_SPACE
#define EL_DF_WALL_START EL_DF_WOODEN_WALL_START
#define EL_DF_WALL_END EL_DF_STEEL_WALL_END
-#define EL_DF_EMPTY (EL_DF_START2 + 304)
+#define EL_DF_EMPTY_SPACE (EL_DF_START2 + 304)
+#define EL_DF_EMPTY EL_DF_EMPTY_SPACE
#define EL_DF_CELL (EL_DF_START2 + 305)
#define EL_DF_MINE (EL_DF_START2 + 306)
#define EL_DF_REFRACTOR (EL_DF_START2 + 307)
#define PROGRAM_VERSION_MAJOR 4
#define PROGRAM_VERSION_MINOR 0
#define PROGRAM_VERSION_PATCH 0
-#define PROGRAM_VERSION_EXTRA "-test-1"
+#define PROGRAM_VERSION_EXTRA "-test-2"
#define PROGRAM_TITLE_STRING "Rocks'n'Diamonds"
#define PROGRAM_AUTHOR_STRING "Holger Schemel"
{ TYPE_SWITCH, &setup.bd_skip_hatching, "Skip hatching player:" },
{ TYPE_SWITCH, &setup.bd_scroll_delay, "Scroll Delay:" },
{ TYPE_YES_NO_AUTO, &setup.bd_smooth_movements, "Smooth Element Movement:" },
- { TYPE_YES_NO_AUTO, &setup.bd_pushing_graphics, "Use Player Pushing Graphics:" },
- { TYPE_YES_NO_AUTO, &setup.bd_up_down_graphics, "Use Player Up/Down Graphics:" },
- { TYPE_YES_NO_AUTO, &setup.bd_skip_falling_sounds, "Mute Double Falling Sounds:" },
+ { TYPE_YES_NO_AUTO, &setup.bd_pushing_graphics, "Player Pushing Graphics:" },
+ { TYPE_YES_NO_AUTO, &setup.bd_up_down_graphics, "Player Up/Down Graphics:" },
+ { TYPE_YES_NO_AUTO, &setup.bd_falling_sounds, "Double Falling Sounds:" },
{ TYPE_SWITCH, &setup.bd_show_invisible_outbox,"Show invisible outbox:" },
{ TYPE_ENTER_LIST, &execSetupChoosePaletteC64, "Color Palette (C64):" },
{ TYPE_STRING, &bd_palette_c64_text, "" },
#if 0
{ TYPE_SWITCH, &setup.editor.el_headlines, "Headlines:" },
#endif
- { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" },
+ { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" },
{ TYPE_SWITCH, &setup.editor.el_dynamic, "Dynamic level elements:" },
{ TYPE_EMPTY, NULL, "" },
#if 0
{ TYPE_SWITCH, &setup.editor.el_by_type, "Show elements by type:" },
{ TYPE_EMPTY, NULL, "" },
#endif
- { TYPE_SWITCH, &setup.editor.show_element_token, "Show element token:" },
+ { TYPE_SWITCH, &setup.editor.show_element_token, "Show element token:" },
+ { TYPE_SWITCH, &setup.editor.fast_game_start, "Fast game start:" },
{ TYPE_EMPTY, NULL, "" },
- { TYPE_SWITCH, &setup.editor.show_read_only_warning, "Show read-only warning:" },
+ { TYPE_SWITCH, &setup.editor.show_read_only_warning, "Show read-only warning:" },
{ TYPE_EMPTY, NULL, "" },
{ TYPE_LEAVE_MENU, execSetupMain, "Back" },
}
}
+static void CheckSaveEngineSnapshot_BD(boolean frame_max,
+ boolean player_moving,
+ boolean player_snapping)
+{
+ if (frame_max)
+ {
+ if (!local_player->was_waiting)
+ {
+ if (!CheckSaveEngineSnapshotToList())
+ return;
+
+ local_player->was_waiting = TRUE;
+ }
+ }
+ else if (player_moving || player_snapping)
+ {
+ local_player->was_waiting = FALSE;
+ }
+}
+
static void CheckSaveEngineSnapshot_EM(int frame,
boolean any_player_moving,
boolean any_player_snapping,
}
}
+boolean CheckSingleStepMode_BD(boolean frame_max,
+ boolean player_moving,
+ boolean player_snapping)
+{
+ if (tape.single_step && tape.recording && !tape.pausing)
+ if (frame_max && FrameCounter > 6)
+ TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+
+ CheckSaveEngineSnapshot_BD(frame_max, player_moving, player_snapping);
+
+ return tape.pausing;
+}
+
boolean CheckSingleStepMode_EM(int frame,
boolean any_player_moving,
boolean any_player_snapping,