added pushable/movable properties for BD bubble (bladder) master-next-major-release 4.4.0.0-test-3
authorHolger Schemel <holger.schemel@virtion.de>
Fri, 5 Jul 2024 06:47:44 +0000 (08:47 +0200)
committerHolger Schemel <holger.schemel@virtion.de>
Fri, 5 Jul 2024 06:47:44 +0000 (08:47 +0200)
48 files changed:
build-projects/android/app/src/main/AndroidManifest.xml.tmpl
build-projects/android/app/src/main/java/org/artsoft/rocksndiamonds/rocksndiamonds.java
docs/elements/bdx_bladder.txt [deleted file]
docs/elements/bdx_bladder_spender.txt [deleted file]
docs/elements/bdx_bubble.txt [new file with mode: 0644]
docs/elements/bdx_diamond_key.txt
docs/elements/bdx_gravity_switch.txt
docs/elements/bdx_pot.txt
docs/elements/bdx_trapped_bubble.txt [new file with mode: 0644]
docs/elements/bdx_trapped_diamond.txt
graphics/gfx_classic/RocksBD.png
graphics/gfx_classic/RocksBD2.png
src/Android.mk
src/conf_gfx.c
src/conf_snd.c
src/editor.c
src/editor.h
src/events.c
src/files.c
src/game.c
src/game_bd/bd_c64import.c
src/game_bd/bd_c64import.h
src/game_bd/bd_cave.c
src/game_bd/bd_cave.h
src/game_bd/bd_cavedb.c
src/game_bd/bd_caveengine.c
src/game_bd/bd_elements.h
src/game_bd/bd_gameplay.c
src/game_bd/bd_gameplay.h
src/game_bd/bd_graphics.c
src/game_bd/bd_graphics.h
src/game_bd/export_bd.h
src/game_bd/import_bd.h
src/game_bd/main_bd.c
src/init.c
src/libgame/misc.c
src/libgame/sdl.c
src/libgame/sdl.h
src/libgame/setup.c
src/libgame/setup.h
src/libgame/system.c
src/libgame/system.h
src/libgame/text.c
src/libgame/zip/ioapi.c
src/main.c
src/main.h
src/screens.c
src/tools.c

index 8331804d0c5a7ddd0730fed9e61a7c2f44832cf4..9a90444fc4247db3d8bd793a5a4d5717ab885f78 100644 (file)
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
                 <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>
 
         </activity>
     </application>
 
index eeec2ea4a4bfe833e180bc2f8c4525200370c632..ee7aed022906797b6d2b2a04a4107a5dfe8724fd 100644 (file)
@@ -3,4 +3,118 @@ package org.artsoft.rocksndiamonds;
 
 import org.libsdl.app.SDLActivity;
 
 
 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 };
+            }
+        }
+    }
+}
diff --git a/docs/elements/bdx_bladder.txt b/docs/elements/bdx_bladder.txt
deleted file mode 100644 (file)
index d4fc834..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Bladders can be pushed around easily. They slowly climb up; if they touch a
-voodoo doll, they convert into clocks. They can also pass slime.
diff --git a/docs/elements/bdx_bladder_spender.txt b/docs/elements/bdx_bladder_spender.txt
deleted file mode 100644 (file)
index 389a72c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-If there is space above it, the bladder spender turns to a bladder.
diff --git a/docs/elements/bdx_bubble.txt b/docs/elements/bdx_bubble.txt
new file mode 100644 (file)
index 0000000..20bab52
--- /dev/null
@@ -0,0 +1,2 @@
+Bubbles can be pushed around easily. They slowly move up; if they touch a
+voodoo doll, they convert into clocks. They can also pass slime.
index 61180d6628d0bf8c57b0f4ed914d7f17bb3e010b..d48974d4bc5532045162bd6f838d02d62c84d5d8 100644 (file)
@@ -1 +1 @@
-If you get this key, all doors will convert into diamonds you can collect.
+If you collect this key, all trapped diamonds will convert into diamonds.
index 6e7d30767ba8caac9e7cbb8ddf59058300cfbf6d..bad7ed5e268decb772e44b432da526cc0d3bea5d 100644 (file)
@@ -1,3 +1,4 @@
-When this switch is active, you can use it to change the gravitation.
-The direction from which you use it will determine the direction the
+When this switch is active, you can push it to change the gravitation.
+The direction into which you push it will determine the direction the
 gravitation will change to.
 gravitation will change to.
+To activate the gravitation switch, the pot has to be stirred first.
index a0239714fa9bf43f884486b5b45464d95ebc978e..d85e6f9a9fdbb820979e7f35614de563c8f90e63 100644 (file)
@@ -1,2 +1,3 @@
 Stir the pot, and you will be able to use the gravitation switch. While you are
 stirring the pot, there is no gravitation at all. Press fire after using the pot.
 Stir the pot, and you will be able to use the gravitation switch. While you are
 stirring the pot, there is no gravitation at all. Press fire after using the pot.
+Before using the pot, a certain number of skeletons have to be collected.
diff --git a/docs/elements/bdx_trapped_bubble.txt b/docs/elements/bdx_trapped_bubble.txt
new file mode 100644 (file)
index 0000000..34d8ae8
--- /dev/null
@@ -0,0 +1,2 @@
+If there is space above it, the trapped bubble turns into a bubble that can move
+up and that can be pushed by the player.
index 484c2cfd5e27666a7ed3e433c78b158d5223e9b6..4344730a3801f301e728b6164f2ebb9433f84d56 100644 (file)
@@ -1 +1,2 @@
-This is an indestructible door with a diamond.
+This is an indestructible door with a trapped diamond.
+To free all trapped diamonds, collect a diamond key.
index 639080c5d183a3b44ae310da8efa0bfa39eacea4..51dd2b6e2b17be58f058d7985fb74e2b800d8a8e 100644 (file)
Binary files a/graphics/gfx_classic/RocksBD.png and b/graphics/gfx_classic/RocksBD.png differ
index 9d937f4c164d32a74ef505933d6ef5cce9a7512c..434e6848ca67d757932dfce4790ae382da85bda1 100644 (file)
Binary files a/graphics/gfx_classic/RocksBD2.png and b/graphics/gfx_classic/RocksBD2.png differ
index a644d93a1b7c85d7ff8b93584a5386b81c326217..f076793a42f80251f41ace9db19f92951220f35c 100644 (file)
@@ -1,7 +1,7 @@
 # =============================================================================
 # Rocks'n'Diamonds - McDuffin Strikes Back!
 # -----------------------------------------------------------------------------
 # =============================================================================
 # 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/
 #                  Holger Schemel
 #                  info@artsoft.org
 #                  https://www.artsoft.org/
@@ -46,6 +46,7 @@ LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.c \
        libgame/image.c                 \
        libgame/random.c                \
        libgame/hash.c                  \
        libgame/image.c                 \
        libgame/random.c                \
        libgame/hash.c                  \
+       libgame/list.c                  \
        libgame/http.c                  \
        libgame/base64.c                \
        libgame/setup.c                 \
        libgame/http.c                  \
        libgame/base64.c                \
        libgame/setup.c                 \
@@ -55,6 +56,19 @@ LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.c \
        libgame/zip/iowin32.c           \
        libgame/zip/unzip.c             \
        libgame/zip/miniunz.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              \
        game_em/cave.c                  \
        game_em/convert.c               \
        game_em/graphics.c              \
index 7262ac97ca94a3cdcd916cbb925593b6eacb42ce..2bc3092146c397bf9ffaabca87ea93fd47452dd1 100644 (file)
@@ -331,6 +331,9 @@ struct ConfigInfo image_config[] =
   { "[bdx_default].growing.delay",                     "4"                             },
   { "[bdx_default].growing.anim_mode",                 "linear"                        },
 
   { "[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_player",                                      UNDEFINED_FILENAME              },
   { "bdx_player.clone_from",                           "player_1"                      },
   { "bdx_player.down",                                 UNDEFINED_FILENAME              },
@@ -695,10 +698,10 @@ struct ConfigInfo image_config[] =
   { "bdx_steelwall_sloped_down_right.frames",          "1"                             },
 
   { "bdx_steelwall_explodable",                                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",                          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_steelwall_diggable.EDITOR",                   "RocksBD2.png"                  },
   { "bdx_steelwall_diggable.EDITOR.xpos",              "6"                             },
   { "bdx_steelwall_diggable.EDITOR.ypos",              "0"                             },
@@ -722,19 +725,19 @@ struct ConfigInfo image_config[] =
   { "bdx_expandable_wall_any.EDITOR.ypos",             "1"                             },
 
   { "bdx_expandable_steelwall_horizontal",             UNDEFINED_FILENAME              },
   { "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_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_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_expandable_steelwall_any.EDITOR",             "RocksBD2.png"                  },
   { "bdx_expandable_steelwall_any.EDITOR.xpos",                "2"                             },
   { "bdx_expandable_steelwall_any.EDITOR.ypos",                "1"                             },
@@ -782,13 +785,13 @@ struct ConfigInfo image_config[] =
   { "bdx_exit_open.EDITOR.ypos",                       "0"                             },
 
   { "bdx_invisible_exit_closed",                       UNDEFINED_FILENAME              },
   { "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_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"                             },
   { "bdx_invisible_exit_open.EDITOR",                  "RocksBD2.png"                  },
   { "bdx_invisible_exit_open.EDITOR.xpos",             "2"                             },
   { "bdx_invisible_exit_open.EDITOR.ypos",             "0"                             },
@@ -850,23 +853,31 @@ struct ConfigInfo image_config[] =
   { "bdx_trapped_diamond.ypos",                                "6"                             },
   { "bdx_trapped_diamond.frames",                      "1"                             },
 
   { "bdx_trapped_diamond.ypos",                                "6"                             },
   { "bdx_trapped_diamond.frames",                      "1"                             },
 
-  { "bdx_nut",                                         UNDEFINED_FILENAME              },
-  { "bdx_nut.clone_from",                              "nut"                           },
+  { "bdx_nut",                                         "RocksBD.png"                   },
+  { "bdx_nut.xpos",                                    "0"                             },
+  { "bdx_nut.ypos",                                    "13"                            },
+  { "bdx_nut.frames",                                  "1"                             },
+  { "bdx_nut.breaking",                                        "RocksBD.png"                   },
+  { "bdx_nut.breaking.xpos",                           "0"                             },
+  { "bdx_nut.breaking.ypos",                           "13"                            },
+  { "bdx_nut.breaking.frames",                         "4"                             },
+  { "bdx_nut.breaking.delay",                          "8"                             },
+  { "bdx_nut.breaking.anim_mode",                      "linear"                        },
   { "bdx_nut.falling.EDITOR",                          "RocksBD2.png"                  },
   { "bdx_nut.falling.EDITOR.xpos",                     "5"                             },
   { "bdx_nut.falling.EDITOR.ypos",                     "2"                             },
 
   { "bdx_nut.falling.EDITOR",                          "RocksBD2.png"                  },
   { "bdx_nut.falling.EDITOR.xpos",                     "5"                             },
   { "bdx_nut.falling.EDITOR.ypos",                     "2"                             },
 
-  { "bdx_bladder",                                     "RocksBD.png"                   },
-  { "bdx_bladder.xpos",                                        "8"                             },
-  { "bdx_bladder.ypos",                                        "12"                            },
-  { "bdx_bladder.frames",                              "4"                             },
-  { "bdx_bladder.delay",                               "4"                             },
-  { "bdx_bladder.anim_mode",                           "pingpong2"                     },
+  { "bdx_bubble",                                      "RocksBD.png"                   },
+  { "bdx_bubble.xpos",                                 "8"                             },
+  { "bdx_bubble.ypos",                                 "12"                            },
+  { "bdx_bubble.frames",                               "4"                             },
+  { "bdx_bubble.delay",                                        "4"                             },
+  { "bdx_bubble.anim_mode",                            "pingpong2"                     },
 
 
-  { "bdx_bladder_spender",                             "RocksBD.png"                   },
-  { "bdx_bladder_spender.xpos",                                "11"                            },
-  { "bdx_bladder_spender.ypos",                                "10"                            },
-  { "bdx_bladder_spender.frames",                      "1"                             },
+  { "bdx_trapped_bubble",                              "RocksBD.png"                   },
+  { "bdx_trapped_bubble.xpos",                         "11"                            },
+  { "bdx_trapped_bubble.ypos",                         "10"                            },
+  { "bdx_trapped_bubble.frames",                       "1"                             },
 
   { "bdx_creature_switch",                             "RocksBD.png"                   },
   { "bdx_creature_switch.xpos",                                "9"                             },
 
   { "bdx_creature_switch",                             "RocksBD.png"                   },
   { "bdx_creature_switch.xpos",                                "9"                             },
@@ -918,7 +929,7 @@ struct ConfigInfo image_config[] =
   { "bdx_conveyor_left.active.xpos",                   "0"                             },
   { "bdx_conveyor_left.active.ypos",                   "3"                             },
   { "bdx_conveyor_left.active.frames",                 "8"                             },
   { "bdx_conveyor_left.active.xpos",                   "0"                             },
   { "bdx_conveyor_left.active.ypos",                   "3"                             },
   { "bdx_conveyor_left.active.frames",                 "8"                             },
-  { "bdx_conveyor_left.active.delay",                  "2"                             },
+  { "bdx_conveyor_left.active.delay",                  "1"                             },
 
   { "bdx_conveyor_right",                              "RocksDC.png"                   },
   { "bdx_conveyor_right.xpos",                         "0"                             },
 
   { "bdx_conveyor_right",                              "RocksDC.png"                   },
   { "bdx_conveyor_right.xpos",                         "0"                             },
@@ -931,7 +942,7 @@ struct ConfigInfo image_config[] =
   { "bdx_conveyor_right.active.xpos",                  "0"                             },
   { "bdx_conveyor_right.active.ypos",                  "3"                             },
   { "bdx_conveyor_right.active.frames",                        "8"                             },
   { "bdx_conveyor_right.active.xpos",                  "0"                             },
   { "bdx_conveyor_right.active.ypos",                  "3"                             },
   { "bdx_conveyor_right.active.frames",                        "8"                             },
-  { "bdx_conveyor_right.active.delay",                 "2"                             },
+  { "bdx_conveyor_right.active.delay",                 "1"                             },
   { "bdx_conveyor_right.active.anim_mode",             "reverse"                       },
 
   { "bdx_conveyor_switch",                             "RocksBD.png"                   },
   { "bdx_conveyor_right.active.anim_mode",             "reverse"                       },
 
   { "bdx_conveyor_switch",                             "RocksBD.png"                   },
@@ -1085,8 +1096,10 @@ struct ConfigInfo image_config[] =
   { "bdx_waiting_rock.EDITOR.xpos",                    "4"                             },
   { "bdx_waiting_rock.EDITOR.ypos",                    "2"                             },
 
   { "bdx_waiting_rock.EDITOR.xpos",                    "4"                             },
   { "bdx_waiting_rock.EDITOR.ypos",                    "2"                             },
 
-  { "bdx_chasing_rock",                                        UNDEFINED_FILENAME              },
-  { "bdx_chasing_rock.clone_from",                     "bdx_rock"                      },
+  { "bdx_chasing_rock",                                        "RocksBD.png"                   },
+  { "bdx_chasing_rock.xpos",                           "0"                             },
+  { "bdx_chasing_rock.ypos",                           "4"                             },
+  { "bdx_chasing_rock.frames",                         "1"                             },
 
   { "bdx_ghost",                                       "RocksBD.png"                   },
   { "bdx_ghost.xpos",                                  "0"                             },
 
   { "bdx_ghost",                                       "RocksBD.png"                   },
   { "bdx_ghost.xpos",                                  "0"                             },
@@ -1363,6 +1376,9 @@ struct ConfigInfo image_config[] =
   { "[sp_default].exploding.delay",                    "4"                             },
   { "[sp_default].exploding.anim_mode",                        "linear"                        },
 
   { "[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"                             },
   { "sp_zonk",                                         "RocksSP.png"                   },
   { "sp_zonk.xpos",                                    "1"                             },
   { "sp_zonk.ypos",                                    "0"                             },
@@ -5514,6 +5530,9 @@ struct ConfigInfo image_config[] =
   { "emc_dripper.active.ypos",                         "8"                             },
   { "emc_dripper.active.frames",                       "1"                             },
 
   { "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_mcduffin",                                     "RocksMM.png"                   },
   { "mm_mcduffin.xpos",                                        "4"                             },
   { "mm_mcduffin.ypos",                                        "1"                             },
@@ -6297,6 +6316,9 @@ struct ConfigInfo image_config[] =
   { "[mm_default].exploding.delay",                    "2"                             },
   { "[mm_default].exploding.anim_mode",                        "linear"                        },
 
   { "[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"                             },
   { "df_laser",                                                "RocksDF.png"                   },
   { "df_laser.xpos",                                   "0"                             },
   { "df_laser.ypos",                                   "9"                             },
index 3b38b50d499c1f5c90cab10b98ce52fa415bc061..103058e4f7b4c51b257fcdb02a3d331574aeeacb 100644 (file)
@@ -64,30 +64,30 @@ struct ConfigInfo sound_config[] =
   { "bd_firefly.waiting",                      "roehr.wav"                     },
 
   // sounds for Boulder Dash style elements and actions (native game engine)
   { "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_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_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_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_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_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_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_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"                     },
   { "bdx_nut.impact",                          "klumpf.wav"                    },
   { "bdx_nitro_pack.pushing",                  "pusch.wav"                     },
   { "bdx_nitro_pack.impact",                   "klopf.wav"                     },
index 0ab5722197222ae67171c807185645aeb65f146c..d2d020faa9a711bf41c8701534ddba6d7774d53c 100644 (file)
@@ -640,7 +640,7 @@ enum
   GADGET_ID_BD_ACID_EATS_ELEMENT,
   GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,
   GADGET_ID_BD_BITER_EATS_ELEMENT,
   GADGET_ID_BD_ACID_EATS_ELEMENT,
   GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,
   GADGET_ID_BD_BITER_EATS_ELEMENT,
-  GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
+  GADGET_ID_BD_BUBBLE_CONVERTS_BY_ELEMENT,
   GADGET_ID_BD_NUT_CONTENT,
   GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
   GADGET_ID_BD_SAND_LOOKS_LIKE,
   GADGET_ID_BD_NUT_CONTENT,
   GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
   GADGET_ID_BD_SAND_LOOKS_LIKE,
@@ -1354,7 +1354,7 @@ enum
   ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
   ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
   ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
   ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
   ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
   ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
-  ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
+  ED_DRAWING_ID_BD_BUBBLE_CONVERTS_BY_ELEMENT,
   ED_DRAWING_ID_BD_NUT_CONTENT,
   ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
   ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
   ED_DRAWING_ID_BD_NUT_CONTENT,
   ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
   ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
@@ -5009,11 +5009,11 @@ static struct
     "Can eat:", NULL, NULL, NULL,              "Eats this element when moving"
   },
   {
     "Can eat:", NULL, NULL, NULL,              "Eats this element when moving"
   },
   {
-    ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
+    ED_DRAWING_ID_BD_BUBBLE_CONVERTS_BY_ELEMENT,
     ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(1),
     ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
     ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(1),
     ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,  GADGET_ID_NONE,
-    &level.bd_bladder_converts_by_element,     1, 1,
+    GADGET_ID_BD_BUBBLE_CONVERTS_BY_ELEMENT,   GADGET_ID_NONE,
+    &level.bd_bubble_converts_by_element,      1, 1,
     "Turns to clock by touching:", NULL, NULL, NULL, "Turns to clock by touching element"
   },
   {
     "Turns to clock by touching:", NULL, NULL, NULL, "Turns to clock by touching element"
   },
   {
@@ -5600,8 +5600,8 @@ static int editor_el_boulderdash_native[] =
   EL_BDX_EXPANDABLE_STEELWALL_ANY,
   EL_BDX_CREATURE_SWITCH,
 
   EL_BDX_EXPANDABLE_STEELWALL_ANY,
   EL_BDX_CREATURE_SWITCH,
 
-  EL_BDX_BLADDER,
-  EL_BDX_BLADDER_SPENDER,
+  EL_BDX_BUBBLE,
+  EL_BDX_TRAPPED_BUBBLE,
   EL_BDX_REPLICATOR,
   EL_BDX_REPLICATOR_SWITCH,
 
   EL_BDX_REPLICATOR,
   EL_BDX_REPLICATOR_SWITCH,
 
@@ -5685,15 +5685,15 @@ static int editor_el_boulderdash_effects[] =
   EL_BDX_EXIT_OPEN,
   EL_BDX_INVISIBLE_EXIT_OPEN,
 
   EL_BDX_EXIT_OPEN,
   EL_BDX_INVISIBLE_EXIT_OPEN,
 
-  EL_BDX_BLADDER_1,
-  EL_BDX_BLADDER_2,
-  EL_BDX_BLADDER_3,
-  EL_BDX_BLADDER_4,
+  EL_BDX_BUBBLE_1,
+  EL_BDX_BUBBLE_2,
+  EL_BDX_BUBBLE_3,
+  EL_BDX_BUBBLE_4,
 
 
-  EL_BDX_BLADDER_5,
-  EL_BDX_BLADDER_6,
-  EL_BDX_BLADDER_7,
-  EL_BDX_BLADDER_8,
+  EL_BDX_BUBBLE_5,
+  EL_BDX_BUBBLE_6,
+  EL_BDX_BUBBLE_7,
+  EL_BDX_BUBBLE_8,
 
   EL_BDX_SAND_2,
   EL_BDX_COW_ENCLOSED_1,
 
   EL_BDX_SAND_2,
   EL_BDX_COW_ENCLOSED_1,
@@ -7389,9 +7389,9 @@ static struct XY xy_directions[] =
 // functions
 // ----------------------------------------------------------------------------
 
 // 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)
 }
 
 static int getMaxInfoTextLength(void)
@@ -11451,6 +11451,20 @@ static void DrawEngineConfigColors(void)
 {
   int i;
 
 {
   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())
   if (bd_color_type_changed)
   {
     if (level.bd_color_type != GD_COLOR_TYPE_RGB && level.bd_color_type != GetCommonColorType_BD())
@@ -12185,7 +12199,7 @@ static struct
                                0, 10                                                           },
   { EL_BDX_CREATURE_SWITCH,    &level.bd_creatures_auto_turn_delay,    TEXT_AUTO_TURN_DELAY    },
   { EL_BDX_GRAVITY_SWITCH,     &level.bd_gravity_switch_delay,         TEXT_GRAVITY_DELAY,
                                0, 10                                                           },
   { EL_BDX_CREATURE_SWITCH,    &level.bd_creatures_auto_turn_delay,    TEXT_AUTO_TURN_DELAY    },
   { EL_BDX_GRAVITY_SWITCH,     &level.bd_gravity_switch_delay,         TEXT_GRAVITY_DELAY,
-                               1, 60                                                           },
+                               0, 60                                                           },
   { EL_EXTRA_TIME,             &level.extra_time,                      TEXT_TIME_BONUS         },
   { EL_TIME_ORB_FULL,          &level.time_orb_time,                   TEXT_TIME_BONUS         },
   { EL_GAME_OF_LIFE,           &level.game_of_life[0],                 TEXT_GAME_OF_LIFE_1,0,8 },
   { EL_EXTRA_TIME,             &level.extra_time,                      TEXT_TIME_BONUS         },
   { EL_TIME_ORB_FULL,          &level.time_orb_time,                   TEXT_TIME_BONUS         },
   { EL_GAME_OF_LIFE,           &level.game_of_life[0],                 TEXT_GAME_OF_LIFE_1,0,8 },
@@ -12451,9 +12465,9 @@ static void DrawPropertiesConfig(void)
     {
       MapDrawingArea(ED_DRAWING_ID_BD_BITER_EATS_ELEMENT);
     }
     {
       MapDrawingArea(ED_DRAWING_ID_BD_BITER_EATS_ELEMENT);
     }
-    else if (properties_element == EL_BDX_BLADDER)
+    else if (properties_element == EL_BDX_BUBBLE)
     {
     {
-      MapDrawingArea(ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT);
+      MapDrawingArea(ED_DRAWING_ID_BD_BUBBLE_CONVERTS_BY_ELEMENT);
     }
     else if (properties_element == EL_YAMYAM ||
             properties_element == EL_YAMYAM_LEFT ||
     }
     else if (properties_element == EL_YAMYAM ||
             properties_element == EL_YAMYAM_LEFT ||
index 96fe6f29140077275d67e987c617f390216b2111..8dd3e390a46648c4408f6be943e7354b5e9db05d 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "main.h"
 
 
 #include "main.h"
 
-boolean isLevelEditorTestGame(void);
+boolean isLevelEditorFastStart(void);
 
 void CreateLevelEditorGadgets(void);
 void FreeLevelEditorGadgets(void);
 
 void CreateLevelEditorGadgets(void);
 void FreeLevelEditorGadgets(void);
index 04f69108527feaca46f5eca02ce2fc30b82f3ad9..99b55fc85824f262bc15915ce469046a5c06a88a 100644 (file)
@@ -1505,7 +1505,8 @@ static int HandleDropFileEvent(char *filename)
   Debug("event:dropfile", "filename == '%s'", filename);
 
   // check and extract dropped zip files into correct user data directory
   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);
 
   {
     Warn("file '%s' not supported", filename);
 
@@ -1615,6 +1616,12 @@ static void HandleDropCompleteEvent(int num_level_sets_succeeded,
 
 void HandleDropEvent(Event *event)
 {
 
 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;
   static boolean confirm_on_drop_complete = FALSE;
   static int num_level_sets_succeeded = 0;
   static int num_artwork_sets_succeeded = 0;
@@ -2095,14 +2102,40 @@ void HandleKey(Key key, int key_status)
     { &ski.snap,  NULL,            DEFAULT_KEY_SNAP,  JOY_BUTTON_SNAP },
     { &ski.drop,  NULL,            DEFAULT_KEY_DROP,  JOY_BUTTON_DROP }
   };
     { &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;
 
   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)
 
   // map special keys (media keys / remote control buttons) to default keys
   if (key == KSYM_PlayPause)
index c620a531b37bf4e30517c01366137a61e78edf8e..589c34dc7e1f5bde3ad6fe49c78f480eda8be202 100644 (file)
@@ -274,7 +274,7 @@ static struct LevelFileConfigInfo chunk_config_INFO[] =
   {
     -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
   {
     -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
-    &li.bd_cycle_delay_ms,             200
+    &li.bd_cycle_delay_ms,             160
   },
   {
     -1,                                        -1,
   },
   {
     -1,                                        -1,
@@ -935,9 +935,9 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
   },
 
   {
   },
 
   {
-    EL_BDX_BLADDER,                    -1,
+    EL_BDX_BUBBLE,                     -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
-    &li.bd_bladder_converts_by_element,        EL_BDX_VOODOO_DOLL
+    &li.bd_bubble_converts_by_element, EL_BDX_VOODOO_DOLL
   },
 
   {
   },
 
   {
@@ -948,7 +948,7 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
   {
     EL_BDX_EXPANDABLE_WALL_ANY,                -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
   {
     EL_BDX_EXPANDABLE_WALL_ANY,                -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
-    &li.bd_expanding_wall_looks_like,  EL_BDX_WALL
+    &li.bd_expanding_wall_looks_like,  EL_BDX_EXPANDABLE_WALL_ANY
   },
 
   {
   },
 
   {
@@ -2924,31 +2924,12 @@ static int getFiletypeFromID(char *filetype_id)
 
 char *getLocalLevelTemplateFilename(void)
 {
 
 char *getLocalLevelTemplateFilename(void)
 {
-  return getDefaultLevelFilename(-1);
+  return getLevelFilenameFromBasename(LEVELTEMPLATE_FILENAME);
 }
 
 char *getGlobalLevelTemplateFilename(void)
 {
 }
 
 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)
 }
 
 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
@@ -4406,7 +4387,7 @@ static void CopyNativeLevel_RND_to_BD(struct LevelInfo *level)
   cave->biter_delay_frame              = level->bd_biter_move_delay;
   cave->biter_eat                      = LEVEL_TO_CAVE(level->bd_biter_eats_element);
 
   cave->biter_delay_frame              = level->bd_biter_move_delay;
   cave->biter_eat                      = LEVEL_TO_CAVE(level->bd_biter_eats_element);
 
-  cave->bladder_converts_by            = LEVEL_TO_CAVE(level->bd_bladder_converts_by_element);
+  cave->bladder_converts_by            = LEVEL_TO_CAVE(level->bd_bubble_converts_by_element);
 
   cave->expanding_wall_changed         = level->bd_change_expanding_wall;
 
 
   cave->expanding_wall_changed         = level->bd_change_expanding_wall;
 
@@ -4579,7 +4560,7 @@ static void CopyNativeLevel_BD_to_RND(struct LevelInfo *level)
   level->bd_biter_move_delay           = cave->biter_delay_frame;
   level->bd_biter_eats_element         = CAVE_TO_LEVEL(cave->biter_eat);
 
   level->bd_biter_move_delay           = cave->biter_delay_frame;
   level->bd_biter_eats_element         = CAVE_TO_LEVEL(cave->biter_eat);
 
-  level->bd_bladder_converts_by_element        = CAVE_TO_LEVEL(cave->bladder_converts_by);
+  level->bd_bubble_converts_by_element = CAVE_TO_LEVEL(cave->bladder_converts_by);
 
   level->bd_change_expanding_wall      = cave->expanding_wall_changed;
 
 
   level->bd_change_expanding_wall      = cave->expanding_wall_changed;
 
@@ -4644,9 +4625,12 @@ static void CopyNativeLevel_BD_to_RND(struct LevelInfo *level)
   SetDefaultLevelColors_BD();
 
   // level name
   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
   level->name[MAX_LEVEL_NAME_LEN] = '\0';
 
   // playfield elements
@@ -4654,7 +4638,8 @@ static void CopyNativeLevel_BD_to_RND(struct LevelInfo *level)
     for (y = 0; y < level->fieldy; y++)
       level->field[x][y] = CAVE_TO_LEVEL(cave->map[y][x]);
 
     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);
 }
 
 static void setTapeInfoToDefaults(void);
@@ -7547,6 +7532,66 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
   LoadLevelFromFileInfo(level, &level_file_info, FALSE);
 }
 
   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;
 static void LoadLevel_InitVersion(struct LevelInfo *level)
 {
   int i, j;
@@ -7738,6 +7783,10 @@ static void LoadLevel_InitVersion(struct LevelInfo *level)
   // 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;
   // 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)
 }
 
 static void LoadLevel_InitSettings_SB(struct LevelInfo *level)
@@ -10842,7 +10891,7 @@ static struct TokenInfo global_setup_tokens[] =
   },
   {
     TYPE_SWITCH_3_STATES,
   },
   {
     TYPE_SWITCH_3_STATES,
-    &setup.bd_skip_falling_sounds,             "bd_skip_falling_sounds"
+    &setup.bd_falling_sounds,                  "bd_falling_sounds"
   },
   {
     TYPE_INTEGER,
   },
   {
     TYPE_INTEGER,
@@ -11060,6 +11109,10 @@ static struct TokenInfo editor_setup_tokens[] =
     TYPE_SWITCH,
     &setup.editor.show_element_token,          "editor.show_element_token"
   },
     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"
   {
     TYPE_SWITCH,
     &setup.editor.show_read_only_warning,      "editor.show_read_only_warning"
@@ -11709,7 +11762,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->bd_smooth_movements = STATE_TRUE;
   si->bd_pushing_graphics = STATE_TRUE;
   si->bd_up_down_graphics = STATE_TRUE;
   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->bd_palette_c64 = GD_DEFAULT_PALETTE_C64;
   si->bd_palette_c64dtv = GD_DEFAULT_PALETTE_C64DTV;
   si->bd_palette_atari = GD_DEFAULT_PALETTE_ATARI;
@@ -11822,6 +11875,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->editor.el_headlines              = TRUE;
 
   si->editor.show_element_token                = FALSE;
   si->editor.el_headlines              = TRUE;
 
   si->editor.show_element_token                = FALSE;
+  si->editor.fast_game_start           = FALSE;
 
   si->editor.show_read_only_warning    = TRUE;
 
 
   si->editor.show_read_only_warning    = TRUE;
 
index 831ec9010a5a0a4a9460d471bb8aaf2574b53045..a516155ce76b269b2704d5ecc3ffe2112899e4c1 100644 (file)
@@ -1840,13 +1840,30 @@ static void InitFieldForEngine_RND(int x, int y)
   int element = Tile[x][y];
 
   // convert BD engine elements to corresponding R'n'D engine elements
   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;
             element);
 
   Tile[x][y] = element;
@@ -2286,7 +2303,7 @@ static void UpdateGameControlValues(void)
   int time = (game.LevelSolved ?
              game.LevelSolved_CountingTime :
              level.game_engine_type == GAME_ENGINE_TYPE_BD ?
   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 ?
              level.game_engine_type == GAME_ENGINE_TYPE_EM ?
              game_em.lev->time :
              level.game_engine_type == GAME_ENGINE_TYPE_SP ?
@@ -4862,9 +4879,10 @@ void InitAmoebaNr(int x, int y)
 
 static void LevelSolved_SetFinalGameValues(void)
 {
 
 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.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 :
                           TimePlayed * FRAMES_PER_SECOND + TimeFrames);
 
   game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.score :
@@ -11835,6 +11853,9 @@ static void CheckLevelTime(void)
     // if last second running, wait for native engine time to exactly reach zero
     if (getTimeLeft_BD() == 1 && TimeLeft == 1)
       TimeFrames = frames_per_second - 1;
     // 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 (TimeFrames >= frames_per_second)
@@ -16591,6 +16612,8 @@ static ListNode *SaveEngineSnapshotBuffers(void)
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
     SaveEngineSnapshotValues_RND();
 
   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_EM)
     SaveEngineSnapshotValues_EM();
   if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
@@ -16602,6 +16625,8 @@ static ListNode *SaveEngineSnapshotBuffers(void)
 
   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_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_EM)
     SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em));
   if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
@@ -16741,6 +16766,8 @@ static void LoadEngineSnapshotValues(void)
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
     LoadEngineSnapshotValues_RND();
 
   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)
   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
     LoadEngineSnapshotValues_EM();
   if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
index b3e0310bb917f48fca5ee1e16d865dd917f03acc..c89fdd020817e3dd2195fc6263aab620596290ef 100644 (file)
@@ -573,6 +573,29 @@ GdEngine gd_cave_get_engine_from_string(const char *param)
 //
 // ============================================================================
 
 //
 // ============================================================================
 
+/*
+ * Checksum function for cave import routines.
+ * Used to recognize caves which need some hacks added,
+ * besides normal importing.
+ * @param data The input array of bytes
+ * @param length The size
+ * @return 16-bit checksum
+ */
+
+static unsigned int checksum(const byte *data, int length)
+{
+  unsigned int a = 1, b = 0;
+  int i;
+
+  for (i = 0; i < length; i++)
+  {
+    a = (a + data[i]) % 251;    // the prime closest to (and less than) 256
+    b = (b + a) % 251;
+  }
+
+  return b * 256 + a;
+}
+
 /*
   take care of required diamonds values == 0 or > 100.
   in original bd, the counter was only two-digit. so bd3 cave f
 /*
   take care of required diamonds values == 0 or > 100.
   in original bd, the counter was only two-digit. so bd3 cave f
@@ -1983,6 +2006,46 @@ static int cave_copy_from_crdr_7(GdCave *cave, const byte *data, int remaining_b
   return 15 + 0x49 + index;
 }
 
   return 15 + 0x49 + index;
 }
 
+// Deluxe Caves 3 hacks
+static void deluxe_caves_3_add_specials(GdCave *cave, const int cavenum)
+{
+  cave->snap_element = O_EXPLODE_1;
+  cave->diagonal_movements = TRUE;
+
+  switch (cavenum)
+  {
+    case 6:     // cave f
+      cave->stone_bouncing_effect = O_BUTTER_1;
+      cave->diamond_falling_effect = O_EXPLODE_3;
+      break;
+
+    case 7:     // cave g
+      Warn("effects not supported");
+      break;
+
+    case 13:    // cave l
+      Warn("effects not working perfectly");
+      cave->stone_bouncing_effect = O_FIREFLY_1;
+      break;
+
+    case 18:
+      cave->diamond_bouncing_effect = O_STONE;
+      break;
+
+    default:
+      break;
+  }
+}
+
+// Crazy Dream 7 hacks
+static void crazy_dream_7_add_specials(GdCave *cave)
+{
+  if (strEqual(cave->name, "Crazy maze"))
+    cave->skeletons_needed_for_pot = 0;
+}
+
+// This function adds some hardcoded elements to a Crazy Dream 9 cave.
+// Crazy Dream 9 had some caves and random fills, which were not encoded in the cave data.
 static void crazy_dream_9_add_specials(GdCave *cave, const byte *buf, const int length)
 {
   byte checksum;
 static void crazy_dream_9_add_specials(GdCave *cave, const byte *buf, const int length)
 {
   byte checksum;
@@ -2061,6 +2124,23 @@ static void crazy_dream_9_add_specials(GdCave *cave, const byte *buf, const int
   }
 }
 
   }
 }
 
+// Masters Boulder hacks
+static void masters_boulder_add_hack(GdCave *cave, const int cavenum)
+{
+  int i;
+
+  switch (cavenum)
+  {
+    case 1:     // cave b
+      for (i = 0; i < 5; i++)
+       cave->level_hatching_delay_time[i] = 3;  // secs
+      break;
+
+    default:
+      break;
+  }
+}
+
 // crazy light contruction kit
 static int cave_copy_from_crli(GdCave *cave, const byte *data, int remaining_bytes)
 {
 // crazy light contruction kit
 static int cave_copy_from_crli(GdCave *cave, const byte *data, int remaining_bytes)
 {
@@ -2421,6 +2501,23 @@ List *gd_caveset_import_from_buffer (const byte *buf, size_t length)
   buf += 12;
   length = encodedlength;
 
   buf += 12;
   length = encodedlength;
 
+  // check for hacks.
+  GdImportHack hack = GD_HACK_NONE;
+  unsigned int cs = checksum(buf, length);
+
+  if (format == GD_FORMAT_PLC    && length == 10240 && cs == 0xbdec)
+    hack = GD_HACK_CRDR_1;
+  if (format == GD_FORMAT_CRLI   && length == 9895  && cs == 0xbc4e)
+    hack = GD_HACK_CRDR_9;
+  if (format == GD_FORMAT_BD1    && length == 1634  && cs == 0xf725)
+    hack = GD_HACK_DC1;
+  if (format == GD_FORMAT_BD1    && length == 1452  && cs == 0xb4a6)
+    hack = GD_HACK_DC3;
+  if (format == GD_FORMAT_CRDR_7 && length == 3759  && cs == 0x16b5)
+    hack = GD_HACK_CRDR_7;
+  if (format == GD_FORMAT_BD1    && length == 1241  && cs == 0x926f)
+    hack = GD_HACK_MB;
+
   bufp = 0;
   cavenum = 0;
 
   bufp = 0;
   cavenum = 0;
 
@@ -2457,6 +2554,10 @@ List *gd_caveset_import_from_buffer (const byte *buf, size_t length)
          case GD_FORMAT_BD1_ATARI:
          case GD_FORMAT_DC1:
            cavelength = cave_copy_from_bd1(newcave, buf + bufp, length - bufp, format);
          case GD_FORMAT_BD1_ATARI:
          case GD_FORMAT_DC1:
            cavelength = cave_copy_from_bd1(newcave, buf + bufp, length - bufp, format);
+           if (cavelength != -1 && hack == GD_HACK_DC3)
+             deluxe_caves_3_add_specials(newcave, cavenum);
+           if (cavelength != -1 && hack == GD_HACK_MB)
+             masters_boulder_add_hack(newcave, cavenum);
            break;
          case GD_FORMAT_BD2:
          case GD_FORMAT_BD2_ATARI:
            break;
          case GD_FORMAT_BD2:
          case GD_FORMAT_BD2_ATARI:
@@ -2483,6 +2584,8 @@ List *gd_caveset_import_from_buffer (const byte *buf, size_t length)
       case GD_FORMAT_PLC:                // peter liepa construction kit
       case GD_FORMAT_PLC_ATARI:          // peter liepa construction kit, atari version
        cavelength = cave_copy_from_plck(newcave, buf + bufp, length - bufp, format);
       case GD_FORMAT_PLC:                // peter liepa construction kit
       case GD_FORMAT_PLC_ATARI:          // peter liepa construction kit, atari version
        cavelength = cave_copy_from_plck(newcave, buf + bufp, length - bufp, format);
+       if (cavelength != -1 && hack == GD_HACK_CRDR_1)
+         newcave->diagonal_movements = TRUE;
        break;
 
       case GD_FORMAT_DLB:
        break;
 
       case GD_FORMAT_DLB:
@@ -2515,11 +2618,13 @@ List *gd_caveset_import_from_buffer (const byte *buf, size_t length)
 
       case GD_FORMAT_CRDR_7:
        cavelength = cave_copy_from_crdr_7 (newcave, buf + bufp, length - bufp);
 
       case GD_FORMAT_CRDR_7:
        cavelength = cave_copy_from_crdr_7 (newcave, buf + bufp, length - bufp);
+       if (cavelength != -1 && hack == GD_HACK_CRDR_7)
+         crazy_dream_7_add_specials(newcave);
        break;
 
       case GD_FORMAT_CRDR_9:
        cavelength = cave_copy_from_crli (newcave, buf + bufp, length - bufp);
        break;
 
       case GD_FORMAT_CRDR_9:
        cavelength = cave_copy_from_crli (newcave, buf + bufp, length - bufp);
-       if (cavelength != -1)
+       if (cavelength != -1 && hack == GD_HACK_CRDR_9)
          crazy_dream_9_add_specials(newcave, buf, cavelength);
        break;
 
          crazy_dream_9_add_specials(newcave, buf, cavelength);
        break;
 
@@ -2554,6 +2659,7 @@ List *gd_caveset_import_from_buffer (const byte *buf, size_t length)
   // try to detect if plc caves are in standard layout.
   // that is, caveset looks like an original, (4 cave,1 intermission)+
   if (format == GD_FORMAT_PLC)
   // try to detect if plc caves are in standard layout.
   // that is, caveset looks like an original, (4 cave,1 intermission)+
   if (format == GD_FORMAT_PLC)
+  {
     // if no selection table stored by any2gdash
     if ((buf[2 + 0x1f0] != buf[2 + 0x1f1] - 1) ||
        (buf[2 + 0x1f0] != 0x19 && buf[2 + 0x1f0] != 0x0e))
     // if no selection table stored by any2gdash
     if ((buf[2 + 0x1f0] != buf[2 + 0x1f1] - 1) ||
        (buf[2 + 0x1f0] != 0x19 && buf[2 + 0x1f0] != 0x0e))
@@ -2583,6 +2689,7 @@ List *gd_caveset_import_from_buffer (const byte *buf, size_t length)
          cave->selectable = (n % 5) == 0;
        }
     }
          cave->selectable = (n % 5) == 0;
        }
     }
+  }
 
   // try to give some names for the caves
   cavenum = 1;
 
   // try to give some names for the caves
   cavenum = 1;
index 979b4254875b2d3c59a151ff28cc2d9f701cb0f2..65f91e166b74e8f361a157100353c5a50386394b 100644 (file)
@@ -41,6 +41,18 @@ typedef enum _gd_cavefile_format
   GD_FORMAT_FIRSTB,     // first boulder
 } GdCavefileFormat;
 
   GD_FORMAT_FIRSTB,     // first boulder
 } GdCavefileFormat;
 
+// import hacks
+typedef enum _gd_import_hack
+{
+  GD_HACK_NONE,         // no hack
+  GD_HACK_CRDR_1,       // crazy dream 1
+  GD_HACK_CRDR_7,       // crazy dream 7
+  GD_HACK_CRDR_9,       // crazy dream 9
+  GD_HACK_DC1,          // deluxe caves 1
+  GD_HACK_DC3,          // deluxe caves 3
+  GD_HACK_MB,           // masters boulder
+} GdImportHack;
+
 // engines
 typedef enum _gd_engine
 {
 // engines
 typedef enum _gd_engine
 {
index 6a22a6379556b13d962f2cd26f7eb293eeb8aa09..7c9586195438d3a37190a3ff9bb8f8e43e75dde6 100644 (file)
@@ -278,20 +278,23 @@ void gd_cave_init(void)
 
   for (i = 0; i < O_MAX; i++)
   {
 
   for (i = 0; i < O_MAX; i++)
   {
-    char *key;
+    char *key_1 = getStringToUpper(gd_elements[i].filename);
 
 
-    key = getStringToUpper(gd_elements[i].filename);
+    if (hashtable_exists(name_to_element, key_1))      // hash value may be 0
+      Warn("Name %s already used for element %x", key_1, i);
 
 
-    if (hashtable_exists(name_to_element, key))                // hash value may be 0
-      Warn("Name %s already used for element %x", key, i);
+    hashtable_insert(name_to_element, key_1, INT_TO_PTR(i));
+    // ^^^ do not free "key_1", as hash table needs it during the whole time!
 
 
-    hashtable_insert(name_to_element, key, INT_TO_PTR(i));
-    // ^^^ do not free "key", as hash table needs it during the whole time!
+    char *key_2 = getStringCat2("SCANNED_", key_1);    // new string
 
 
-    key = getStringCat2("SCANNED_", key);              // new string
+    hashtable_insert(name_to_element, key_2, INT_TO_PTR(i));
+    // once again, do not free "key_2" ^^^
 
 
-    hashtable_insert(name_to_element, key, INT_TO_PTR(i));
-    // once again, do not free "key" ^^^
+    char *key_3 = getStringCat2("SCANN_", key_1);      // new string
+
+    hashtable_insert(name_to_element, key_3, INT_TO_PTR(i));
+    // once again, do not free "key_3" ^^^
   }
 
   // for compatibility with tim stridmann's memorydump->bdcff converter... .... ...
   }
 
   // for compatibility with tim stridmann's memorydump->bdcff converter... .... ...
@@ -1317,7 +1320,8 @@ void gd_cave_count_diamonds(GdCave *cave)
   by the caller.
 */
 void gd_drawcave_game(const GdCave *cave,
   by the caller.
 */
 void gd_drawcave_game(const GdCave *cave,
-                     int **element_buffer, int **last_element_buffer, int **gfx_buffer,
+                     int **element_buffer, int **last_element_buffer,
+                     int **drawing_buffer, int **last_drawing_buffer, int **gfx_buffer,
                      boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox)
 {
   static int player_blinking = 0;
                      boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox)
 {
   static int player_blinking = 0;
@@ -1581,8 +1585,11 @@ void gd_drawcave_game(const GdCave *cave,
        draw += GD_NUM_OF_CELLS;
 
       // set to buffer, with caching
        draw += GD_NUM_OF_CELLS;
 
       // set to buffer, with caching
-      if (element_buffer[y][x] != map)
-       element_buffer[y][x] = map;
+      if (element_buffer[y][x] != actual)
+       element_buffer[y][x] = actual;
+
+      if (drawing_buffer[y][x] != map)
+       drawing_buffer[y][x] = map;
 
       if (gfx_buffer[y][x] != draw)
        gfx_buffer[y][x] = draw | GD_REDRAW;
 
       if (gfx_buffer[y][x] != draw)
        gfx_buffer[y][x] = draw | GD_REDRAW;
@@ -1661,7 +1668,7 @@ void gd_cave_adler_checksum_more(GdCave *cave, unsigned int *a, unsigned int *b)
   for (y = 0; y < cave->h; y++)
     for (x = 0; x < cave->w; x++)
     {
   for (y = 0; y < cave->h; y++)
     for (x = 0; x < cave->w; x++)
     {
-      *a += gd_elements[cave->map[y][x]].character;
+      *a += gd_elements[cave->map[y][x] & O_MASK].character;
       *b += *a;
 
       *a %= 65521;
       *b += *a;
 
       *a %= 65521;
index 1a85776a68a4e17333308881e7c8807d1fe144c3..becee295d36180a57ad246531b29dabf384a91a1 100644 (file)
@@ -121,11 +121,14 @@ enum _element_property
   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_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
   E_P_CAN_MOVE,                 // can move
   E_P_CAN_FALL,                 // can fall
   E_P_DIGGABLE,                 // can be digged
   E_P_COLLECTIBLE,              // can be collected
   E_P_PUSHABLE,                 // can be pushed
   E_P_CAN_MOVE,                 // can move
   E_P_CAN_FALL,                 // can fall
+  E_P_CAN_GROW,                 // can grow
+  E_P_CAN_DIG,                  // can dig
   E_P_FALLING,                  // falling
   E_P_GROWING,                  // growing (element birth)
 };
   E_P_FALLING,                  // falling
   E_P_GROWING,                  // growing (element birth)
 };
@@ -160,11 +163,14 @@ enum _element_property
 #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_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)
 #define P_CAN_MOVE                     (1 << E_P_CAN_MOVE)
 #define P_CAN_FALL                     (1 << E_P_CAN_FALL)
 #define P_DIGGABLE                     (1 << E_P_DIGGABLE)
 #define P_COLLECTIBLE                  (1 << E_P_COLLECTIBLE)
 #define P_PUSHABLE                     (1 << E_P_PUSHABLE)
 #define P_CAN_MOVE                     (1 << E_P_CAN_MOVE)
 #define P_CAN_FALL                     (1 << E_P_CAN_FALL)
+#define P_CAN_GROW                     (1 << E_P_CAN_GROW)
+#define P_CAN_DIG                      (1 << E_P_CAN_DIG)
 #define P_FALLING                      (1 << E_P_FALLING)
 #define P_GROWING                      (1 << E_P_GROWING)
 
 #define P_FALLING                      (1 << E_P_FALLING)
 #define P_GROWING                      (1 << E_P_GROWING)
 
@@ -702,7 +708,8 @@ GdScheduling gd_scheduling_from_string(const char *str);
 #define GD_REDRAW (1 << 10)
 
 void gd_drawcave_game(const GdCave *cave,
 #define GD_REDRAW (1 << 10)
 
 void gd_drawcave_game(const GdCave *cave,
-                     int **element_buffer, int **last_element_buffer, int **gfx_buffer,
+                     int **element_buffer, int **last_element_buffer,
+                     int **drawing_buffer, int **last_drawing_buffer, int **gfx_buffer,
                      boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox);
 
 // function to copy a GdString
                      boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox);
 
 // function to copy a GdString
index 45da297ee1ca8376262cc6a971db70cf5ab1c09b..9c3b02a3755b27d76af86e4d875e87f180de31e3 100644 (file)
@@ -118,7 +118,7 @@ enum _generated_cells_indexes
 */
 GdElements gd_elements[] =
 {
 */
 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_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 },
@@ -162,12 +162,12 @@ GdElements gd_elements[] =
   { O_NUT_F, N_("Nut, falling"), P_FALLING, "NUTf", 0, i_nut_f, i_nut_f, 358, 156 },    // has ckdelay
   { O_BLADDER_SPENDER, N_("Bladder Spender"), P_PUSHABLE, "BLADDERSPENDER", 0, 6, 6, 6, 20 },    // has ckdelay
   { O_INBOX, N_("Inbox"), 0, "INBOX", 'P', 35, 35, 22 },
   { O_NUT_F, N_("Nut, falling"), P_FALLING, "NUTf", 0, i_nut_f, i_nut_f, 358, 156 },    // has ckdelay
   { O_BLADDER_SPENDER, N_("Bladder Spender"), P_PUSHABLE, "BLADDERSPENDER", 0, 6, 6, 6, 20 },    // has ckdelay
   { O_INBOX, N_("Inbox"), 0, "INBOX", 'P', 35, 35, 22 },
-  { O_H_EXPANDING_WALL, N_("Expanding wall, horizontal"), P_VISUAL_EFFECT | P_CAN_BE_HAMMERED, "HEXPANDINGWALL", 'x', i_h_expanding_wall, i_h_expanding_wall, 5, 111 },    // has ckdelay
-  { O_V_EXPANDING_WALL, N_("Expanding wall, vertical"), P_VISUAL_EFFECT | P_CAN_BE_HAMMERED, "VEXPANDINGWALL", 'v', i_v_expanding_wall, i_v_expanding_wall, 5, 111 },    // has ckdelay
-  { O_EXPANDING_WALL, N_("Expanding wall"), P_VISUAL_EFFECT | P_CAN_BE_HAMMERED, "EXPANDINGWALL", 'e', i_expanding_wall, i_expanding_wall, 5, 111 },    // has ckdelay
-  { O_H_EXPANDING_STEEL_WALL, N_("Expanding steel wall, horizontal"), P_NON_EXPLODABLE, "HEXPANDINGSTEELWALL", 0, i_h_expanding_steel_wall, i_h_expanding_steel_wall, 4, 111 },    // has ckdelay
-  { O_V_EXPANDING_STEEL_WALL, N_("Expanding steel wall, vertical"), P_NON_EXPLODABLE, "VEXPANDINGSTEELWALL", 0, i_v_expanding_steel_wall, i_v_expanding_steel_wall, 4, 111 },    // has ckdelay
-  { O_EXPANDING_STEEL_WALL, N_("Expanding steel wall"), P_NON_EXPLODABLE, "EXPANDINGSTEELWALL", 0, i_expanding_steel_wall, i_expanding_steel_wall, 4, 111 },    // has ckdelay
+  { O_H_EXPANDING_WALL, N_("Expanding wall, horizontal"), P_VISUAL_EFFECT | P_CAN_BE_HAMMERED | P_CAN_GROW, "HEXPANDINGWALL", 'x', i_h_expanding_wall, i_h_expanding_wall, 5, 111 },    // has ckdelay
+  { O_V_EXPANDING_WALL, N_("Expanding wall, vertical"), P_VISUAL_EFFECT | P_CAN_BE_HAMMERED | P_CAN_GROW, "VEXPANDINGWALL", 'v', i_v_expanding_wall, i_v_expanding_wall, 5, 111 },    // has ckdelay
+  { O_EXPANDING_WALL, N_("Expanding wall"), P_VISUAL_EFFECT | P_CAN_BE_HAMMERED | P_CAN_GROW, "EXPANDINGWALL", 'e', i_expanding_wall, i_expanding_wall, 5, 111 },    // has ckdelay
+  { O_H_EXPANDING_STEEL_WALL, N_("Expanding steel wall, horizontal"), P_NON_EXPLODABLE | P_CAN_GROW, "HEXPANDINGSTEELWALL", 0, i_h_expanding_steel_wall, i_h_expanding_steel_wall, 4, 111 },    // has ckdelay
+  { O_V_EXPANDING_STEEL_WALL, N_("Expanding steel wall, vertical"), P_NON_EXPLODABLE | P_CAN_GROW, "VEXPANDINGSTEELWALL", 0, i_v_expanding_steel_wall, i_v_expanding_steel_wall, 4, 111 },    // has ckdelay
+  { O_EXPANDING_STEEL_WALL, N_("Expanding steel wall"), P_NON_EXPLODABLE | P_CAN_GROW, "EXPANDINGSTEELWALL", 0, i_expanding_steel_wall, i_expanding_steel_wall, 4, 111 },    // has ckdelay
   { O_EXPANDING_WALL_SWITCH, N_("Expanding wall switch"), 0, "EXPANDINGWALLSWITCH", 0, 40, 40, 40 },
   { O_CREATURE_SWITCH, N_("Creature direction switch"), 0, "FIREFLYBUTTERFLYSWITCH", 0, 18, 18, 18 },
   { O_BITER_SWITCH, N_("Biter switch"), 0, "BITERSWITCH", 0, 12, 12, 12 },
   { O_EXPANDING_WALL_SWITCH, N_("Expanding wall switch"), 0, "EXPANDINGWALLSWITCH", 0, 40, 40, 40 },
   { O_CREATURE_SWITCH, N_("Creature direction switch"), 0, "FIREFLYBUTTERFLYSWITCH", 0, 18, 18, 18 },
   { O_BITER_SWITCH, N_("Biter switch"), 0, "BITERSWITCH", 0, 12, 12, 12 },
@@ -196,7 +196,7 @@ GdElements gd_elements[] =
   { 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_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 },
   { 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 },
@@ -231,8 +231,8 @@ GdElements gd_elements[] =
   { O_WALLED_KEY_2, N_("Walled key 2"), P_CAN_BE_HAMMERED, "WALLED_KEY2", 0, i_walled_key_2, i_walled_key_2, 5 },
   { O_WALLED_KEY_3, N_("Walled key 3"), P_CAN_BE_HAMMERED, "WALLED_KEY3", 0, i_walled_key_3, i_walled_key_3, 5 },
 
   { O_WALLED_KEY_2, N_("Walled key 2"), P_CAN_BE_HAMMERED, "WALLED_KEY2", 0, i_walled_key_2, i_walled_key_2, 5 },
   { O_WALLED_KEY_3, N_("Walled key 3"), P_CAN_BE_HAMMERED, "WALLED_KEY3", 0, i_walled_key_3, i_walled_key_3, 5 },
 
-  { O_AMOEBA, N_("Amoeba"), P_BLOWS_UP_FLIES | P_CAN_MOVE, "AMOEBA", 'a', 192, -192, -192, 260 },    // has ckdelay
-  { O_AMOEBA_2, N_("Amoeba 2"), P_BLOWS_UP_FLIES | P_CAN_MOVE | P_VISUAL_EFFECT, "AMOEBA2", 0, 296, -296, -296, 260 },    // has ckdelay
+  { O_AMOEBA, N_("Amoeba"), P_BLOWS_UP_FLIES | P_CAN_GROW | P_CAN_DIG, "AMOEBA", 'a', 192, -192, -192, 260 },    // has ckdelay
+  { O_AMOEBA_2, N_("Amoeba 2"), P_BLOWS_UP_FLIES | P_CAN_GROW | P_CAN_DIG | P_VISUAL_EFFECT, "AMOEBA2", 0, 296, -296, -296, 260 },    // has ckdelay
   { O_REPLICATOR, N_("Replicator"), P_NON_EXPLODABLE, "REPLICATOR", 0, 304, -304, -304, 210 },    // has ckdelay
   { O_CONVEYOR_LEFT, N_("Conveyor belt (left)"), P_NON_EXPLODABLE, "CONVEYORLEFT", 0, i_conveyor_left, -328, -328, 256  },    // has ckdelay
   { O_CONVEYOR_RIGHT, N_("Conveyor belt (right)"), P_NON_EXPLODABLE, "CONVEYORRIGHT", 0, i_conveyor_right, -320, -320  },
   { O_REPLICATOR, N_("Replicator"), P_NON_EXPLODABLE, "REPLICATOR", 0, 304, -304, -304, 210 },    // has ckdelay
   { O_CONVEYOR_LEFT, N_("Conveyor belt (left)"), P_NON_EXPLODABLE, "CONVEYORLEFT", 0, i_conveyor_left, -328, -328, 256  },    // has ckdelay
   { O_CONVEYOR_RIGHT, N_("Conveyor belt (right)"), P_NON_EXPLODABLE, "CONVEYORRIGHT", 0, i_conveyor_right, -320, -320  },
@@ -240,15 +240,15 @@ GdElements gd_elements[] =
   { O_SWEET, N_("Sweet"), P_COLLECTIBLE, "SWEET", 0, 8, 8, 8 },
   { O_VOODOO, N_("Voodoo doll"), P_BLOWS_UP_FLIES, "DUMMY", 'F', 7, 7, 7 },
   { O_SLIME, N_("Slime"), 0, "SLIME", 's', 200, -200, -200, 211 },        // has ckdelay
   { O_SWEET, N_("Sweet"), P_COLLECTIBLE, "SWEET", 0, 8, 8, 8 },
   { O_VOODOO, N_("Voodoo doll"), P_BLOWS_UP_FLIES, "DUMMY", 'F', 7, 7, 7 },
   { O_SLIME, N_("Slime"), 0, "SLIME", 's', 200, -200, -200, 211 },        // has ckdelay
-  { O_BLADDER, N_("Bladder"), 0, "BLADDER", 0, 176, -176, -176, 267 },    // has ckdelay
-  { O_BLADDER_1, N_("Bladder (1)"), 0, "BLADDERd1", 0, 176, -176, -176 },
-  { O_BLADDER_2, N_("Bladder (2)"), 0, "BLADDERd2", 0, 176, -176, -176 },
-  { O_BLADDER_3, N_("Bladder (3)"), 0, "BLADDERd3", 0, 176, -176, -176 },
-  { O_BLADDER_4, N_("Bladder (4)"), 0, "BLADDERd4", 0, 176, -176, -176 },
-  { O_BLADDER_5, N_("Bladder (5)"), 0, "BLADDERd5", 0, 176, -176, -176 },
-  { O_BLADDER_6, N_("Bladder (6)"), 0, "BLADDERd6", 0, 176, -176, -176 },
-  { O_BLADDER_7, N_("Bladder (7)"), 0, "BLADDERd7", 0, 176, -176, -176 },
-  { O_BLADDER_8, N_("Bladder (8)"), 0, "BLADDERd8", 0, 176, -176, -176 },
+  { O_BLADDER, N_("Bladder"), P_PUSHABLE | P_CAN_MOVE, "BLADDER", 0, 176, -176, -176, 267 },    // has ckdelay
+  { O_BLADDER_1, N_("Bladder (1)"), P_PUSHABLE | P_CAN_MOVE, "BLADDERd1", 0, 176, -176, -176 },
+  { O_BLADDER_2, N_("Bladder (2)"), P_PUSHABLE | P_CAN_MOVE, "BLADDERd2", 0, 176, -176, -176 },
+  { O_BLADDER_3, N_("Bladder (3)"), P_PUSHABLE | P_CAN_MOVE, "BLADDERd3", 0, 176, -176, -176 },
+  { O_BLADDER_4, N_("Bladder (4)"), P_PUSHABLE | P_CAN_MOVE, "BLADDERd4", 0, 176, -176, -176 },
+  { O_BLADDER_5, N_("Bladder (5)"), P_PUSHABLE | P_CAN_MOVE, "BLADDERd5", 0, 176, -176, -176 },
+  { O_BLADDER_6, N_("Bladder (6)"), P_PUSHABLE | P_CAN_MOVE, "BLADDERd6", 0, 176, -176, -176 },
+  { O_BLADDER_7, N_("Bladder (7)"), P_PUSHABLE | P_CAN_MOVE, "BLADDERd7", 0, 176, -176, -176 },
+  { O_BLADDER_8, N_("Bladder (8)"), P_PUSHABLE | P_CAN_MOVE, "BLADDERd8", 0, 176, -176, -176 },
 
   { O_WAITING_STONE, N_("Waiting stone"), P_SLOPED | P_PUSHABLE, "WAITINGBOULDER", 0, i_waiting_stone, i_waiting_stone, 1, 176 },    // has ckdelay
   { O_CHASING_STONE, N_("Chasing stone"), P_SLOPED | P_CAN_MOVE | P_PUSHABLE, "CHASINGBOULDER", 0, 17, 17, 17, 269 },    // has ckdelay
 
   { O_WAITING_STONE, N_("Waiting stone"), P_SLOPED | P_PUSHABLE, "WAITINGBOULDER", 0, i_waiting_stone, i_waiting_stone, 1, 176 },    // has ckdelay
   { O_CHASING_STONE, N_("Chasing stone"), P_SLOPED | P_CAN_MOVE | P_PUSHABLE, "CHASINGBOULDER", 0, 17, 17, 17, 269 },    // has ckdelay
@@ -285,21 +285,21 @@ GdElements gd_elements[] =
   { O_PRE_PL_1, N_("Player birth (1)"), P_GROWING, "GUYBIRTH1", 0, 32, 32, 32 },
   { O_PRE_PL_2, N_("Player birth (2)"), P_GROWING, "GUYBIRTH2", 0, 33, 33, 33 },
   { O_PRE_PL_3, N_("Player birth (3)"), P_GROWING, "GUYBIRTH3", 0, 34, 34, 34 },
   { O_PRE_PL_1, N_("Player birth (1)"), P_GROWING, "GUYBIRTH1", 0, 32, 32, 32 },
   { O_PRE_PL_2, N_("Player birth (2)"), P_GROWING, "GUYBIRTH2", 0, 33, 33, 33 },
   { O_PRE_PL_3, N_("Player birth (3)"), P_GROWING, "GUYBIRTH3", 0, 34, 34, 34 },
-  { O_PLAYER, N_("Player"), P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER, "GUY", 0, i_player, i_player, 35, 32 },    // has ckdelay
-  { O_PLAYER_BOMB, N_("Player with bomb"), P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER, "GUYBOMB", 0, 42, 42, 42, 25 },    // has ckdelay
-  { O_PLAYER_ROCKET_LAUNCHER, N_("Player with rocket launcher"), P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER, "GUYROCKETLAUNCER", 0, 369, 369, 369, 25 },    // has ckdelay
+  { O_PLAYER, N_("Player"), P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER | P_CAN_DIG, "GUY", 0, i_player, i_player, 35, 32 },    // has ckdelay
+  { O_PLAYER_BOMB, N_("Player with bomb"), P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER | P_CAN_DIG, "GUYBOMB", 0, 42, 42, 42, 25 },    // has ckdelay
+  { O_PLAYER_ROCKET_LAUNCHER, N_("Player with rocket launcher"), P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER | P_CAN_DIG, "GUYROCKETLAUNCER", 0, 369, 369, 369, 25 },    // has ckdelay
   { O_PLAYER_GLUED, N_("Glued player"), P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT, "GUYGLUED", 0, i_player_glued, i_player_glued, 35 },    // is not a real player! so active x, y will not find it. no P_PLAYER bit!
   { O_PLAYER_STIRRING, N_("Player stirring"), P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER, "GUYSTIRRING", 0, 256, -256, -256 },
 
   { O_ROCKET_LAUNCHER, N_("Rocket launcher"), 0, "ROCKET_LAUNCHER", 0, 368, 368, 368 },
   { O_PLAYER_GLUED, N_("Glued player"), P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT, "GUYGLUED", 0, i_player_glued, i_player_glued, 35 },    // is not a real player! so active x, y will not find it. no P_PLAYER bit!
   { O_PLAYER_STIRRING, N_("Player stirring"), P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER, "GUYSTIRRING", 0, 256, -256, -256 },
 
   { O_ROCKET_LAUNCHER, N_("Rocket launcher"), 0, "ROCKET_LAUNCHER", 0, 368, 368, 368 },
-  { O_ROCKET_1, N_("Rocket (right)"), 0, "ROCKETr", 0, 364, 364, 364, 40 },    // has ckdelay
-  { O_ROCKET_2, N_("Rocket (up)"), 0, "ROCKETu", 0, 365, 365, 365, 40 },    // has ckdelay
-  { O_ROCKET_3, N_("Rocket (left)"), 0, "ROCKETl", 0, 366, 366, 366, 40 },    // has ckdelay
-  { O_ROCKET_4, N_("Rocket (down)"), 0, "ROCKETd", 0, 367, 367, 367, 40 },    // has ckdelay
-
-  { O_BOMB, N_("Bomb"), P_COLLECTIBLE, "BOMB", 0, 48, 48, 48 },
-  { O_BOMB_TICK_1, N_("Ticking bomb (1)"), P_EXPLOSION_FIRST_STAGE, "IGNITEDBOMB1", 0, 49, 49, 49 },
-  { O_BOMB_TICK_2, N_("Ticking bomb (2)"), 0, "IGNITEDBOMB2", 0, 50, 50, 50 },
+  { O_ROCKET_1, N_("Rocket (right)"), P_CAN_MOVE, "ROCKETr", 0, 364, 364, 364, 40 },    // has ckdelay
+  { O_ROCKET_2, N_("Rocket (up)"), P_CAN_MOVE, "ROCKETu", 0, 365, 365, 365, 40 },    // has ckdelay
+  { O_ROCKET_3, N_("Rocket (left)"), P_CAN_MOVE, "ROCKETl", 0, 366, 366, 366, 40 },    // has ckdelay
+  { O_ROCKET_4, N_("Rocket (down)"), P_CAN_MOVE, "ROCKETd", 0, 367, 367, 367, 40 },    // has ckdelay
+
+  { O_BOMB, N_("Bomb"), P_COLLECTIBLE | P_CAN_MOVE, "BOMB", 0, 48, 48, 48 },
+  { O_BOMB_TICK_1, N_("Ticking bomb (1)"), P_EXPLOSION_FIRST_STAGE | P_CAN_DIG, "IGNITEDBOMB1", 0, 49, 49, 49 },
+  { O_BOMB_TICK_2, N_("Ticking bomb (2)"), P_CAN_DIG, "IGNITEDBOMB2", 0, 50, 50, 50 },
   { O_BOMB_TICK_3, N_("Ticking bomb (3)"), 0, "IGNITEDBOMB3", 0, 51, 51, 51 },
   { O_BOMB_TICK_4, N_("Ticking bomb (4)"), 0, "IGNITEDBOMB4", 0, 52, 52, 52 },
   { O_BOMB_TICK_5, N_("Ticking bomb (5)"), 0, "IGNITEDBOMB5", 0, 53, 53, 53 },
   { O_BOMB_TICK_3, N_("Ticking bomb (3)"), 0, "IGNITEDBOMB3", 0, 51, 51, 51 },
   { O_BOMB_TICK_4, N_("Ticking bomb (4)"), 0, "IGNITEDBOMB4", 0, 52, 52, 52 },
   { O_BOMB_TICK_5, N_("Ticking bomb (5)"), 0, "IGNITEDBOMB5", 0, 53, 53, 53 },
@@ -353,8 +353,8 @@ GdElements gd_elements[] =
   { O_NUT_EXPL_3, N_("Nut explosion (3)"), P_SLOPED | P_EXPLOSION, "NUTEXPLOSION3", 0, 362, 362, 362, 280 },    // has ckdelay
   { O_NUT_EXPL_4, N_("Nut explosion (4)"), P_SLOPED | P_EXPLOSION, "NUTEXPLOSION4", 0, 363, 363, 363, 280 },    // has ckdelay
 
   { O_NUT_EXPL_3, N_("Nut explosion (3)"), P_SLOPED | P_EXPLOSION, "NUTEXPLOSION3", 0, 362, 362, 362, 280 },    // has ckdelay
   { O_NUT_EXPL_4, N_("Nut explosion (4)"), P_SLOPED | P_EXPLOSION, "NUTEXPLOSION4", 0, 363, 363, 363, 280 },    // has ckdelay
 
-  { O_PLAYER_PNEUMATIC_LEFT, NULL /* Player using hammer, left */, P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER, "GUYHAMMERl", 0, 265, 265, 265 },
-  { O_PLAYER_PNEUMATIC_RIGHT, NULL /* Player using hammer, right */, P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER, "GUYHAMMERr", 0, 268, 268, 268 },
+  { O_PLAYER_PNEUMATIC_LEFT, NULL /* Player using hammer, left */, P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER | P_CAN_DIG, "GUYHAMMERl", 0, 265, 265, 265 },
+  { O_PLAYER_PNEUMATIC_RIGHT, NULL /* Player using hammer, right */, P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER | P_CAN_DIG, "GUYHAMMERr", 0, 268, 268, 268 },
   { O_PNEUMATIC_ACTIVE_LEFT, NULL /* Active hammer, left */, 0, "HAMMERACTIVEl", 0, 264, 264, 264 },
   { O_PNEUMATIC_ACTIVE_RIGHT, NULL /* Active hammer, right */, 0, "HAMMERACTIVEr", 0, 269, 269, 269 },
 
   { O_PNEUMATIC_ACTIVE_LEFT, NULL /* Active hammer, left */, 0, "HAMMERACTIVEl", 0, 264, 264, 264 },
   { O_PNEUMATIC_ACTIVE_RIGHT, NULL /* Active hammer, right */, 0, "HAMMERACTIVEr", 0, 269, 269, 269 },
 
@@ -372,10 +372,10 @@ GdElements gd_elements[] =
   { O_OUTBOX_CLOSED, NULL, 0, NULL, 0, 22, 22, 22 },
   { O_OUTBOX_OPEN, NULL, 0, NULL, 0, 23, 23, 23 },
   { O_COVERED, NULL, 0, NULL, 0, 128, -128, -128 },
   { O_OUTBOX_CLOSED, NULL, 0, NULL, 0, 22, 22, 22 },
   { O_OUTBOX_OPEN, NULL, 0, NULL, 0, 23, 23, 23 },
   { O_COVERED, NULL, 0, NULL, 0, 128, -128, -128 },
-  { O_PLAYER_LEFT, NULL, P_PLAYER, NULL, 0, 232, -232, -232 },
-  { O_PLAYER_RIGHT, NULL, P_PLAYER, NULL, 0, 240, -240, -240 },
-  { O_PLAYER_UP, NULL, P_PLAYER, NULL, 0, 376, -376, -376 },
-  { O_PLAYER_DOWN, NULL, P_PLAYER, NULL, 0, 384, -384, -384 },
+  { O_PLAYER_LEFT, NULL, P_PLAYER | P_CAN_DIG, NULL, 0, 232, -232, -232 },
+  { O_PLAYER_RIGHT, NULL, P_PLAYER | P_CAN_DIG, NULL, 0, 240, -240, -240 },
+  { O_PLAYER_UP, NULL, P_PLAYER | P_CAN_DIG, NULL, 0, 376, -376, -376 },
+  { O_PLAYER_DOWN, NULL, P_PLAYER | P_CAN_DIG, NULL, 0, 384, -384, -384 },
   { O_PLAYER_TAP, NULL, P_PLAYER, NULL, 0, 216, -216, -216 },
   { O_PLAYER_BLINK, NULL, P_PLAYER, NULL, 0, 208, -208, -208 },
   { O_PLAYER_TAP_BLINK, NULL, P_PLAYER, NULL, 0, 224, -224, -224 },
   { O_PLAYER_TAP, NULL, P_PLAYER, NULL, 0, 216, -216, -216 },
   { O_PLAYER_BLINK, NULL, P_PLAYER, NULL, 0, 208, -208, -208 },
   { O_PLAYER_TAP_BLINK, NULL, P_PLAYER, NULL, 0, 224, -224, -224 },
index ee1b4ee2f9740ba97664dba40ad1a5324e59b0d3..4c3b7b0ae72cbbf38db09505c65bfa3acc480789 100644 (file)
@@ -43,7 +43,8 @@ static const GdDirection ccw_eighth[] =
   GD_MV_RIGHT,
   GD_MV_DOWN_RIGHT,
   GD_MV_DOWN,
   GD_MV_RIGHT,
   GD_MV_DOWN_RIGHT,
   GD_MV_DOWN,
-  GD_MV_DOWN_LEFT
+  GD_MV_DOWN_LEFT,
+  GD_MV_LEFT
 };
 
 static const GdDirection ccw_fourth[] =
 };
 
 static const GdDirection ccw_fourth[] =
@@ -56,8 +57,7 @@ static const GdDirection ccw_fourth[] =
   GD_MV_RIGHT,
   GD_MV_DOWN_RIGHT,
   GD_MV_DOWN,
   GD_MV_RIGHT,
   GD_MV_DOWN_RIGHT,
   GD_MV_DOWN,
-  GD_MV_DOWN_LEFT,
-  GD_MV_LEFT
+  GD_MV_DOWN_LEFT
 };
 
 static const GdDirection cw_eighth[] =
 };
 
 static const GdDirection cw_eighth[] =
@@ -132,11 +132,23 @@ static inline boolean el_can_fall(const int element)
   return (gd_elements[element & O_MASK].properties & P_CAN_FALL) != 0;
 }
 
   return (gd_elements[element & O_MASK].properties & P_CAN_FALL) != 0;
 }
 
+// returns true if the element is diggable
+static inline boolean el_diggable(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_DIGGABLE) != 0;
+}
+
+// returns true if the element can smash the player
+static inline boolean el_can_smash_player(const int element)
+{
+  return (el_can_fall(element) && !el_diggable(element));
+}
+
 // play diamond or stone sound of given element.
 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)
 // play diamond or stone sound of given element.
 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.
     return;
 
   // stone and diamond fall sounds.
@@ -543,6 +555,9 @@ static inline boolean is_space_dir(const GdCave *cave, const int x, const int y,
 
 static inline void store_dir_buffer(GdCave *cave, const int x, const int y, const GdDirection dir)
 {
 
 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];
   // raw values without range correction
   int raw_x = x + gd_dx[dir];
   int raw_y = y + gd_dy[dir];
@@ -552,7 +567,18 @@ static inline void store_dir_buffer(GdCave *cave, const int x, const int y, cons
   int new_y = gety(cave, raw_x, raw_y);
   int new_dir = (dir > GD_MV_TWICE ? dir - GD_MV_TWICE : 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
 }
 
 // store an element at the given position
@@ -596,6 +622,19 @@ static inline void store_dir_no_scanned(GdCave *cave, const int x, const int y,
 static inline void move(GdCave *cave, const int x, const int y,
                        const GdDirection dir, const GdElement e)
 {
 static inline void move(GdCave *cave, const int x, const int y,
                        const GdDirection dir, const GdElement e)
 {
+  // falling/flying game elements at wrap-around cave position should not kill player instantly
+  if ((x + gd_dx[dir] == cave->w && dir == GD_MV_RIGHT) ||
+      (y + gd_dy[dir] == cave->h && dir == GD_MV_DOWN))
+  {
+    // cave width/height out of bounds, but due to wrap-around it's the first column/row again
+    if (el_can_smash_player(get(cave, x, y)))
+    {
+      store(cave, x, y, e); // change to falling element ...
+
+      return;               // ... but do not move element
+    }
+  }
+
   store_dir(cave, x, y, dir, e);
   store(cave, x, y, O_SPACE);
 }
   store_dir(cave, x, y, dir, e);
   store(cave, x, y, O_SPACE);
 }
@@ -1570,6 +1609,9 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
 
   gd_cave_clear_sounds(cave);
 
 
   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 diagonal movements not allowed,
   // horizontal movements have precedence. [BROADRIBB]
   if (!cave->diagonal_movements)
@@ -1696,7 +1738,7 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
       }
 
       // add the ckdelay correction value for every element seen.
       }
 
       // add the ckdelay correction value for every element seen.
-      cave->ckdelay += gd_elements[get(cave, x, y)].ckdelay;
+      cave->ckdelay += gd_elements[get(cave, x, y) & O_MASK].ckdelay;
 
       switch (get(cave, x, y))
       {
 
       switch (get(cave, x, y))
       {
@@ -1813,8 +1855,9 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
                       player_move == GD_MV_DOWN))
                  {
                    gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
                       player_move == GD_MV_DOWN))
                  {
                    gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
+                    // (use 1 instead of 0 for immediate gravitation change)
                    cave->gravity_will_change =
                    cave->gravity_will_change =
-                     cave->gravity_change_time * cave->timing_factor;
+                     MAX(1, cave->gravity_change_time * cave->timing_factor);
                    cave->gravity_next_direction = player_move;
                    cave->gravity_switch_active = FALSE;
                  }
                    cave->gravity_next_direction = player_move;
                    cave->gravity_switch_active = FALSE;
                  }
@@ -1835,15 +1878,25 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
              // if snapping anything and we have snapping explosions set.
              // but these is not true for pushing.
              if (remains == O_SPACE && player_fire && !push)
              // 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;
 
                remains = cave->snap_element;
 
+               game_bd.player_snapping = TRUE;
+              }
+
              if (remains != O_SPACE || player_fire)
              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);
                // 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
              else
+              {
                // if space remains there, the player moves.
                move(cave, x, y, player_move, O_PLAYER);
                // if space remains there, the player moves.
                move(cave, x, y, player_move, O_PLAYER);
+
+               game_bd.player_moving = TRUE;
+              }
            }
          }
          break;
            }
          }
          break;
@@ -1909,8 +1962,9 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
                       player_move == GD_MV_DOWN))
                  {
                    gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
                       player_move == GD_MV_DOWN))
                  {
                    gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
+                    // (use 1 instead of 0 for immediate gravitation change)
                    cave->gravity_will_change =
                    cave->gravity_will_change =
-                     cave->gravity_change_time * cave->timing_factor;
+                     MAX(1, cave->gravity_change_time * cave->timing_factor);
                    cave->gravity_next_direction = player_move;
                    cave->gravity_switch_active = FALSE;
                  }
                    cave->gravity_next_direction = player_move;
                    cave->gravity_switch_active = FALSE;
                  }
@@ -3291,8 +3345,27 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
              if (!is_scanned_dir(cave, x, y, GD_MV_UP) &&
                  is_space_dir(cave, x, y, dir[GD_MV_UP]))
              {
              if (!is_scanned_dir(cave, x, y, GD_MV_UP) &&
                  is_space_dir(cave, x, y, dir[GD_MV_UP]))
              {
-               store_dir(cave, x, y, dir[GD_MV_UP], get_dir(cave, x, y, GD_MV_UP));    // move
-               store_dir(cave, x, y, GD_MV_UP, O_SPACE);    // and place a space.
+                // to allow smooth movement of game elements on conveyor belts,
+                // the moving direction set by "store_dir()" must be set to the
+                // direction the game element on the conveyor belt is moving;
+                // without smooth movement, the following lines would do it:
+                //
+               // store_dir(cave, x, y, dir[GD_MV_UP], get_dir(cave, x, y, GD_MV_UP));    // move
+               // store_dir(cave, x, y, GD_MV_UP, O_SPACE);    // and place a space.
+
+               int tile = get_dir(cave, x, y, GD_MV_UP);
+                int move_dir = (left ? GD_MV_LEFT : GD_MV_RIGHT); // top side direction
+
+                // raw values without range correction
+                int raw_x = x + gd_dx[GD_MV_UP];
+                int raw_y = y + gd_dy[GD_MV_UP];
+
+                // final values with range correction
+                int old_x = getx(cave, raw_x, raw_y);
+                int old_y = gety(cave, raw_x, raw_y);
+
+               store_dir(cave, x, y, GD_MV_UP, O_SPACE);        // place a space ...
+               store_dir(cave, old_x, old_y, move_dir, tile);   // and move element.
              }
            }
 
              }
            }
 
@@ -3305,8 +3378,27 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
              if (!is_scanned_dir(cave, x, y, GD_MV_DOWN) &&
                  is_space_dir(cave, x, y, dir[GD_MV_DOWN]))
              {
              if (!is_scanned_dir(cave, x, y, GD_MV_DOWN) &&
                  is_space_dir(cave, x, y, dir[GD_MV_DOWN]))
              {
-               store_dir(cave, x, y, dir[GD_MV_DOWN], get_dir(cave, x, y, GD_MV_DOWN));    // move
-               store_dir(cave, x, y, GD_MV_DOWN, O_SPACE);    // and clear.
+                // to allow smooth movement of game elements on conveyor belts,
+                // the moving direction set by "store_dir()" must be set to the
+                // direction the game element on the conveyor belt is moving;
+                // without smooth movement, the following lines would do it:
+                //
+               // store_dir(cave, x, y, dir[GD_MV_DOWN], get_dir(cave, x, y, GD_MV_DOWN)); // move
+               // store_dir(cave, x, y, GD_MV_DOWN, O_SPACE);    // and clear.
+
+               int tile = get_dir(cave, x, y, GD_MV_DOWN);
+                int move_dir = (left ? GD_MV_RIGHT : GD_MV_LEFT); // bottom side direction
+
+                // raw values without range correction
+                int raw_x = x + gd_dx[GD_MV_DOWN];
+                int raw_y = y + gd_dy[GD_MV_DOWN];
+
+                // final values with range correction
+                int old_x = getx(cave, raw_x, raw_y);
+                int old_y = gety(cave, raw_x, raw_y);
+
+               store_dir(cave, x, y, GD_MV_DOWN, O_SPACE);      // place a space ...
+               store_dir(cave, old_x, old_y, move_dir, tile);   // and move element.
              }
            }
          }
              }
            }
          }
@@ -3720,7 +3812,9 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
     if (cave->gravity_will_change == 0)
     {
       cave->gravity = cave->gravity_next_direction;
     if (cave->gravity_will_change == 0)
     {
       cave->gravity = cave->gravity_next_direction;
-      gd_sound_play(cave, GD_S_GRAVITY_CHANGING, O_GRAVITY_SWITCH, -1, -1);    // takes precedence over amoeba and magic wall sound
+
+      // takes precedence over amoeba and magic wall sound
+      gd_sound_play(cave, GD_S_GRAVITY_CHANGING, O_GRAVITY_SWITCH, -1, -1);
     }
   }
 
     }
   }
 
@@ -3910,7 +4004,7 @@ void set_initial_cave_speed(GdCave *cave)
     for (x = 0; x < cave->w; x++)
     {
       // add the ckdelay correction value for every element seen.
     for (x = 0; x < cave->w; x++)
     {
       // add the ckdelay correction value for every element seen.
-      cave->ckdelay += gd_elements[get(cave, x, y)].ckdelay;
+      cave->ckdelay += gd_elements[get(cave, x, y) & O_MASK].ckdelay;
     }
   }
 
     }
   }
 
index dd36b1ee0ff391b8661cac9c84cf8d333022567b..9beef2fee0023ef395c850d76854d67644eb4fd1 100644 (file)
@@ -317,12 +317,11 @@ typedef enum _element
 
   O_MAX_ALL,
 
 
   O_MAX_ALL,
 
-  SCANNED = 0x100,
-  COVERED = 0x200,
-  SKIPPED = 0x400,
+  SCANNED = 0x400,
+  COVERED = 0x800,
 
   // binary AND this to elements to get rid of properties above.
 
   // binary AND this to elements to get rid of properties above.
-  O_MASK = ~(SCANNED | COVERED | SKIPPED)
+  O_MASK = ~(SCANNED | COVERED)
 } GdElement;
 
 typedef enum _sound
 } GdElement;
 
 typedef enum _sound
index 12eb53bcca2ba1c7e8699e3af954f96907e75c33..b157bdf0640f04fcbfb726a4fca3bfb469e1c221 100644 (file)
@@ -26,8 +26,14 @@ void gd_game_free(GdGame *game)
     gd_cave_map_free(game->element_buffer);
   if (game->last_element_buffer)
     gd_cave_map_free(game->last_element_buffer);
     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->drawing_buffer)
+    gd_cave_map_free(game->drawing_buffer);
+  if (game->last_drawing_buffer)
+    gd_cave_map_free(game->last_drawing_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);
 
   if (game->gfx_buffer)
     gd_cave_map_free(game->gfx_buffer);
 
@@ -89,10 +95,25 @@ static void load_cave(GdGame *game)
     gd_cave_map_free(game->last_element_buffer);
   game->last_element_buffer = NULL;
 
     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 drawing buffer
+  if (game->drawing_buffer)
+    gd_cave_map_free(game->drawing_buffer);
+  game->drawing_buffer = NULL;
+
+  // delete last drawing buffer
+  if (game->last_drawing_buffer)
+    gd_cave_map_free(game->last_drawing_buffer);
+  game->last_drawing_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)
 
   // delete gfx buffer
   if (game->gfx_buffer)
@@ -122,6 +143,8 @@ static void load_cave(GdGame *game)
   game->milliseconds_anim = 0;
   game->milliseconds_game = 0;        // set game timer to zero, too
 
   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);
 
   // create new element buffer
   game->element_buffer = gd_cave_map_new(game->cave, int);
 
@@ -136,12 +159,33 @@ static void load_cave(GdGame *game)
     for (x = 0; x < game->cave->w; x++)
       game->last_element_buffer[y][x] = O_NONE;
 
     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 drawing buffer
+  game->drawing_buffer = gd_cave_map_new(game->cave, int);
 
   for (y = 0; y < game->cave->h; y++)
     for (x = 0; x < game->cave->w; x++)
 
   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->drawing_buffer[y][x] = O_NONE;
+
+  // create new last drawing buffer
+  game->last_drawing_buffer = gd_cave_map_new(game->cave, int);
+
+  for (y = 0; y < game->cave->h; y++)
+    for (x = 0; x < game->cave->w; x++)
+      game->last_drawing_buffer[y][x] = O_NONE;
+
+  // 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_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);
 
   // create new gfx buffer
   game->gfx_buffer = gd_cave_map_new(game->cave, int);
@@ -188,6 +232,13 @@ GdGame *gd_game_new(const int cave, const int level)
   return game;
 }
 
   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;
 static void iterate_cave(GdGame *game, GdDirection player_move, boolean fire)
 {
   boolean suicide = FALSE;
@@ -364,12 +415,15 @@ static GdGameState gd_game_main_int(GdGame *game, boolean allow_iterate, boolean
     // normally nothing happes. but if we iterate, this might change.
     return_state = GD_GAME_NOTHING;
 
     // normally nothing happes. but if we iterate, this might change.
     return_state = GD_GAME_NOTHING;
 
-    // if allowing cave movements, add elapsed time to timer. and then we can check what to do.
+    // if allowing cave movements, ...
     if (allow_iterate)
     if (allow_iterate)
+    {
+      // ... add elapsed time to timer. and then we can check what to do
       game->milliseconds_game += millisecs_elapsed;
 
       game->milliseconds_game += millisecs_elapsed;
 
-    // increment cycle (frame) counter for the current cave iteration
-    game->itercycle++;
+      // ... increment cycle (frame) counter for the current cave iteration
+      game->itercycle++;
+    }
 
     if (game->milliseconds_game >= cavespeed)
     {
 
     if (game->milliseconds_game >= cavespeed)
     {
@@ -383,22 +437,29 @@ static GdGameState gd_game_main_int(GdGame *game, boolean allow_iterate, boolean
       {
        for (x = 0; x < game->cave->w; x++)
        {
       {
        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->last_drawing_buffer[y][x] = game->drawing_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;
 
       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->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;
       if (game->player_move == GD_MV_STILL)
       {
        game->player_move_stick = FALSE;
@@ -566,8 +627,9 @@ static GdGameState gd_game_main_int(GdGame *game, boolean allow_iterate, boolean
 
   // always render the cave to the gfx buffer;
   // however it may do nothing if animcycle was not changed.
 
   // always render the cave to the gfx buffer;
   // however it may do nothing if animcycle was not changed.
-  if (game->element_buffer && game->gfx_buffer)
-    gd_drawcave_game(game->cave, game->element_buffer, game->last_element_buffer, game->gfx_buffer,
+  if (game->element_buffer && game->drawing_buffer && game->gfx_buffer)
+    gd_drawcave_game(game->cave, game->element_buffer, game->last_element_buffer,
+                    game->drawing_buffer, game->last_drawing_buffer, game->gfx_buffer,
                     game->bonus_life_flash != 0, game->animcycle, setup.bd_show_invisible_outbox);
 
   game->state_counter = counter_next;
                     game->bonus_life_flash != 0, game->animcycle, setup.bd_show_invisible_outbox);
 
   game->state_counter = counter_next;
@@ -621,7 +683,7 @@ void play_game_func(GdGame *game, int action)
   // if drawcave was before scrolling, it would draw, scroll would invalidate,
   // and then it should be drawn again
   // only do the drawing if the cave already exists.
   // if drawcave was before scrolling, it would draw, scroll would invalidate,
   // and then it should be drawn again
   // only do the drawing if the cave already exists.
-  if (game->cave && game->element_buffer && game->gfx_buffer)
+  if (game->cave && game->element_buffer && game->drawing_buffer && game->gfx_buffer)
   {
     // if fine scrolling, scroll at 50hz. if not, only scroll at every second call, so 25hz.
     // do the scrolling. scroll exactly, if player is not yet alive
   {
     // if fine scrolling, scroll at 50hz. if not, only scroll at every second call, so 25hz.
     // do the scrolling. scroll exactly, if player is not yet alive
index aa9a48de387be6ec127c0e09cc5853798353800f..fbeeecfcce94a54a3fd21df5792b08c3abffdcb8 100644 (file)
@@ -77,15 +77,20 @@ typedef struct _gd_game
   int state_counter;            // counter used to control the game flow, rendering of caves
   int **element_buffer;
   int **last_element_buffer;
   int state_counter;            // counter used to control the game flow, rendering of caves
   int **element_buffer;
   int **last_element_buffer;
-  int **dir_buffer;
+  int **drawing_buffer;
+  int **last_drawing_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 **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 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.
 
   int replay_no_more_movements;
   boolean show_story;          // to remember that story for a particular cave was already shown.
@@ -112,6 +117,8 @@ GdGame *gd_game_new(const int cave, const int level);
 GdGame *gd_game_new_snapshot(GdCave *snapshot);
 GdGame *gd_game_new_test(GdCave *cave, int level);
 
 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
 void play_game_func(GdGame *game, int action);
 
 #endif // BD_GAMEPLAY_H
index aa091ba131b44404613d50aebcdde97ce18ee4d6..793987e285c985a8840d2f0e73d558803e61b363 100644 (file)
@@ -334,6 +334,11 @@ boolean gd_scroll(GdGame *game, boolean exact_scroll, boolean immediate)
     scroll_speed_last = -1;
 
   // check if active player is visible at the moment.
     scroll_speed_last = -1;
 
   // check if active player is visible at the moment.
+  // but only if scrolling happened at all!
+  if (!changed)
+    return FALSE;
+
+  // check if active player is outside drawing area. if yes, we should wait for scrolling.
   return player_out_of_window(game, player_x, player_y);
 }
 
   return player_out_of_window(game, player_x, player_y);
 }
 
@@ -363,6 +368,11 @@ static boolean surface_has_c64_colors(SDL_Surface *surface)
   return has_c64_colors;
 }
 
   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)
 {
 // 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)
 {
@@ -466,8 +476,14 @@ static Bitmap *get_tile_bitmap_c64(GdCave *cave, SDL_Surface *surface)
   set_surface_palette_color(surface, 7, 0);
   set_surface_palette_color(surface, 8, 0);
 
   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
   // 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 tile_bitmap_c64;
 }
@@ -532,6 +548,14 @@ static inline boolean el_player(const int element)
   return (gd_elements[element & O_MASK].properties & P_PLAYER) != 0;
 }
 
   return (gd_elements[element & O_MASK].properties & P_PLAYER) != 0;
 }
 
+#if 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;
+}
+#endif
+
 // returns true if the element is diggable
 static inline boolean el_diggable(const int element)
 {
 // returns true if the element is diggable
 static inline boolean el_diggable(const int element)
 {
@@ -558,6 +582,24 @@ static inline boolean el_can_move(const int element)
   return (gd_elements[element & O_MASK].properties & P_CAN_MOVE) != 0;
 }
 
   return (gd_elements[element & O_MASK].properties & P_CAN_MOVE) != 0;
 }
 
+// returns true if the element can fall
+static inline boolean el_can_fall(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_CAN_FALL) != 0;
+}
+
+// returns true if the element can grow
+static inline boolean el_can_grow(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_CAN_GROW) != 0;
+}
+
+// returns true if the element can dig
+static inline boolean el_can_dig(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_CAN_DIG) != 0;
+}
+
 // returns true if the element can fall
 static inline boolean el_falling(const int element)
 {
 // returns true if the element can fall
 static inline boolean el_falling(const int element)
 {
@@ -576,6 +618,22 @@ static inline boolean el_explosion(const int element)
   return (gd_elements[element & O_MASK].properties & P_EXPLOSION) != 0;
 }
 
   return (gd_elements[element & O_MASK].properties & P_EXPLOSION) != 0;
 }
 
+static inline boolean el_smooth_movable(const int element)
+{
+  // special case of non-moving player
+  if (element == O_PLAYER_PNEUMATIC_LEFT ||
+      element == O_PLAYER_PNEUMATIC_RIGHT)
+    return FALSE;
+
+  return (el_player(element) ||
+          el_can_move(element) ||
+          el_can_fall(element) ||
+          el_can_grow(element) ||
+          el_can_dig(element) ||
+          el_falling(element) ||
+          el_pushable(element));
+}
+
 static void gd_drawcave_tile(Bitmap *dest, GdGame *game, int x, int y, boolean draw_masked)
 {
   void (*blit_bitmap)(Bitmap *, Bitmap *, int, int, int, int, int, int) =
 static void gd_drawcave_tile(Bitmap *dest, GdGame *game, int x, int y, boolean draw_masked)
 {
   void (*blit_bitmap)(Bitmap *, Bitmap *, int, int, int, int, int, int) =
@@ -583,51 +641,102 @@ static void gd_drawcave_tile(Bitmap *dest, GdGame *game, int x, int y, boolean d
   GdCave *cave = game->cave;
   int sx = x * cell_size - scroll_x;
   int sy = y * cell_size - scroll_y;
   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 = game->element_buffer[y][x];
+  int draw = game->drawing_buffer[y][x];
+  int tile_last = game->last_element_buffer[y][x];
+  int draw_last = game->last_drawing_buffer[y][x];
+  int tile_from = O_NONE;      // source element if element is moving (will be set later)
+  int draw_from = O_NONE;      // source element if element is moving (will be set later)
+  int tile_to = tile;          // target element if element is moving
+  int draw_to = draw;          // target element if element is moving
   int frame = game->animcycle;
   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();
 
   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)
+    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);
+    int new_dir_to = game->dir_buffer_to[new_y][new_x];
+
+    tile_from = game->element_buffer[new_y][new_x];
+    draw_from = game->drawing_buffer[new_y][new_x];
+
+    // handle special case of player running into enemy/explosion from top or left side
+    if (el_player(tile_last) && (el_growing(tile_from) || el_explosion(tile_from)))
+      tile_from = tile_last;
+
+    // handle special case of player digging or snapping clock (which gets replaced by sand)
+    if (el_diggable(tile_from) && el_player(tile))
+      use_smooth_movements = FALSE;
+
+    // do not use smooth movement if from and to directions are different; for example,
+    // player has snapped field, but another element immediately moved to that field
+    if (dir_from != new_dir_to)
+      use_smooth_movements = FALSE;
+
+    // handle special case of element falling or moving into lava
+    if (tile_from == O_LAVA)
     {
     {
-      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);
+      // show element that is moving/falling into lava
+      tile_from = tile_last;
+      draw_from = draw_last;
 
 
-      game->element_buffer[y][x] = tile;
+      // do not use smooth movement if element not moving into lava (like player snapping lava)
+      if (tile == tile_last)
+        use_smooth_movements = FALSE;
     }
 
     }
 
-    use_smooth_movements = FALSE;
+    // player killed by lava or explosion was standing still before moving into lava or enemy
+    if (el_player(tile_from))
+      draw_from = (dir_from == GD_MV_LEFT  ? O_PLAYER_LEFT  :
+                   dir_from == GD_MV_RIGHT ? O_PLAYER_RIGHT :
+                   dir_from == GD_MV_UP    ? O_PLAYER_UP    :
+                   dir_from == GD_MV_DOWN  ? O_PLAYER_DOWN  : O_PLAYER);
+
+    // do not use smooth movement if tile has stopped falling and crashed something (like a nut)
+    if (el_can_fall(tile) && el_explosion(tile_from))
+      use_smooth_movements = FALSE;
   }
 
   }
 
+  // --------------------------------------------------------------------------------
+  // 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;
 
   // 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;
+
+  // do not use smooth movement animation for game elements that cannot move smoothly
+  // (but handle special case of player digging or snapping diggable element, like sand)
+  if (!el_smooth_movable(tile_from) &&
+      !el_smooth_movable(tile_to) &&
+      !el_diggable(tile_last))
+    use_smooth_movements = FALSE;
+
 #if DO_GFX_SANITY_CHECK
   if (use_native_bd_graphics_engine() && !setup.small_game_graphics && !program.headless)
   {
 #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[draw][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;
     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;
@@ -636,10 +745,10 @@ static void gd_drawcave_tile(Bitmap *dest, GdGame *game, int x, int y, boolean d
     if (new_x != old_x || new_y != old_y)
     {
       printf("::: BAD ANIMATION FOR TILE %d, FRAME %d [NEW(%d, %d) != OLD(%d, %d)] ['%s']\n",
     if (new_x != old_x || new_y != old_y)
     {
       printf("::: BAD ANIMATION FOR TILE %d, FRAME %d [NEW(%d, %d) != OLD(%d, %d)] ['%s']\n",
-            tile, frame,
+            draw, frame,
             new_x, new_y,
             old_x, old_y,
             new_x, new_y,
             old_x, old_y,
-            gd_elements[tile].name);
+            gd_elements[draw].name);
     }
   }
 #endif
     }
   }
 #endif
@@ -647,74 +756,79 @@ static void gd_drawcave_tile(Bitmap *dest, GdGame *game, int x, int y, boolean d
   // if game element not moving (or no smooth movements requested), simply draw tile
   if (!is_moving || !use_smooth_movements)
   {
   // 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[draw][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;
   }
 
     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
   // draw smooth animation for game element moving between two cave tiles
+  // --------------------------------------------------------------------------------
 
 
-  if (!(game->last_element_buffer[y][x] & SKIPPED))
+  // ---------- 1st step: draw background element for this tile ----------
   {
   {
-    // redraw previous game element on the cave field the new element is moving to
-    int tile_last = game->last_element_buffer[y][x];
+    // check if player or amoeba is digging or player is snapping a diggable game element
+    boolean digging_tile = ((el_can_dig(tile) || tile == O_SPACE) && el_diggable(tile_last));
+    int draw_back = (!is_moving_to ? draw : digging_tile ? draw_last : O_SPACE);
+    struct GraphicInfo_BD *g = &graphic_info_bd_object[draw_back][frame];
+    Bitmap *tile_bitmap = gd_get_tile_bitmap(g->bitmap);
 
 
-    // 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)
-  {
-    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);
-
-      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;
 
   }
 
   // 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[draw_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_diggable(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[draw_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;
   }
 }
 
   }
 }
 
@@ -759,12 +873,9 @@ int gd_drawcave(Bitmap *dest, GdGame *game, boolean force_redraw)
     {
       if (redraw_all ||
          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;
 
        // now we have drawn it
        game->gfx_buffer[y][x] = game->gfx_buffer[y][x] & ~GD_REDRAW;
 
index 6b522fcc504143d767ddbc23d864e2fdefbd1112..e52048adadf1f4891fb249189535286e85b1345c 100644 (file)
@@ -33,6 +33,7 @@ int get_play_area_h(void);
 
 void gd_init_play_area(void);
 
 
 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);
 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);
index a060e2e4be7f5f07990d10aa2560747968cf74ba..a50b9e9f5d817ba66f58e9c2c792e17d2a9f5d49 100644 (file)
@@ -43,10 +43,16 @@ struct GameInfo_BD
   boolean game_over;
   boolean cover_screen;
 
   boolean game_over;
   boolean cover_screen;
 
+  boolean player_moving;
+  boolean player_snapping;
+
   // needed for updating panel
   // needed for updating panel
-  int time_played;
+  int time_left;
   int gems_still_needed;
   int score;
   int gems_still_needed;
   int score;
+
+  // needed for saving score time
+  int frames_played;
 };
 
 struct LevelInfo_BD
 };
 
 struct LevelInfo_BD
@@ -72,6 +78,22 @@ struct GraphicInfo_BD
 
 struct EngineSnapshotInfo_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 drawing_buffer[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+  int last_drawing_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];
 };
 
 
 };
 
 
@@ -96,6 +118,7 @@ boolean checkGamePlaying_BD(void);
 boolean checkBonusTime_BD(void);
 int getFramesPerSecond_BD(void);
 int getTimeLeft_BD(void);
 boolean checkBonusTime_BD(void);
 int getFramesPerSecond_BD(void);
 int getTimeLeft_BD(void);
+void SetTimeFrames_BD(int);
 
 void InitGfxBuffers_BD(void);
 
 
 void InitGfxBuffers_BD(void);
 
@@ -117,7 +140,9 @@ boolean use_native_bd_graphics_engine(void);
 boolean use_bd_smooth_movements(void);
 boolean use_bd_pushing_graphics(void);
 boolean use_bd_up_down_graphics(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);
 
 Bitmap **GetTitleScreenBitmaps_BD(void);
 void CoverScreen_BD(void);
@@ -125,4 +150,7 @@ void CoverScreen_BD(void);
 void BlitScreenToBitmap_BD(Bitmap *);
 void RedrawPlayfield_BD(boolean);
 
 void BlitScreenToBitmap_BD(Bitmap *);
 void RedrawPlayfield_BD(boolean);
 
+void SaveEngineSnapshotValues_BD(void);
+void LoadEngineSnapshotValues_BD(void);
+
 #endif // EXPORT_BD_H
 #endif // EXPORT_BD_H
index ace426dbfdcbfcb5833fe2470297bbf8687b81ca..75e801c00d6115a2db6eef52eef2b01406da33fc 100644 (file)
@@ -27,6 +27,7 @@
 // ----------------------------------------------------------------------------
 
 void InitGraphicInfo_BD(void);
 // ----------------------------------------------------------------------------
 
 void InitGraphicInfo_BD(void);
+boolean CheckSingleStepMode_BD(boolean, boolean, boolean);
 
 void PlayLevelSound_BD(int, int, int, int);
 void StopSound_BD(int, int);
 
 void PlayLevelSound_BD(int, int, int, int);
 void StopSound_BD(int, int);
@@ -38,6 +39,6 @@ byte *TapePlayAction_BD(void);
 byte *TapeCorrectAction_BD(byte *);
 boolean TapeIsPlaying_ReplayBD(void);
 
 byte *TapeCorrectAction_BD(byte *);
 boolean TapeIsPlaying_ReplayBD(void);
 
-boolean isLevelEditorTestGame(void);
+boolean isLevelEditorFastStart(void);
 
 #endif // IMPORT_BD_H
 
 #endif // IMPORT_BD_H
index 06ecfd0458fa7cea799a9fe044236b56122a75b9..9f94b3b68596799f92d87dd5fa1bd7b475c09ca4 100644 (file)
@@ -255,20 +255,28 @@ int getTimeLeft_BD(void)
   return 0;
 }
 
   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;
 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));
 
   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_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.LevelSolved_CountingScore = game_bd.score;
   }
 }
@@ -320,10 +328,6 @@ void InitGameEngine_BD(void)
   game_bd.game_over = FALSE;
   game_bd.cover_screen = FALSE;
 
   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;
 
   gd_caveset_last_selected       = native_bd_level.cave_nr;
   gd_caveset_last_selected_level = native_bd_level.level_nr;
 
@@ -335,6 +339,11 @@ void InitGameEngine_BD(void)
   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->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;
 
   // default: start with completely covered playfield
   int next_state = GAME_INT_START_UNCOVER + 1;
@@ -356,10 +365,10 @@ void InitGameEngine_BD(void)
   // when skipping uncovering, continue with uncovered playfield
   if (setup.bd_skip_uncovering)
     game_bd.game->state_counter = GAME_INT_UNCOVER_ALL + 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;
 
     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);
     gd_scroll(game_bd.game, TRUE, TRUE);
 
   ClearRectangle(gd_screen_bitmap, 0, 0, SXSIZE, SYSIZE);
@@ -433,6 +442,15 @@ void GameActions_BD(byte action[MAX_PLAYERS])
     play_game_func(game_bd.game, action[0]);
   }
 
     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();
   RedrawPlayfield_BD(FALSE);
 
   UpdateGameDoorValues_BD();
@@ -470,11 +488,16 @@ boolean use_bd_up_down_graphics(void)
          (setup.bd_up_down_graphics == STATE_AUTO && !use_native_bd_graphics_engine()));
 }
 
          (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)
 }
 
 Bitmap **GetTitleScreenBitmaps_BD(void)
@@ -531,3 +554,105 @@ void RedrawPlayfield_BD(boolean force_redraw)
 {
   gd_drawcave(gd_screen_bitmap, game_bd.game, force_redraw);
 }
 {
   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.drawing_buffer[x][y]      = game->drawing_buffer[y][x];
+      engine_snapshot_bd.last_drawing_buffer[x][y] = game->last_drawing_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.drawing_buffer      = game->drawing_buffer;
+  engine_snapshot_bd.game.last_drawing_buffer = game->last_drawing_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->drawing_buffer[y][x]      = engine_snapshot_bd.drawing_buffer[x][y];
+      game->last_drawing_buffer[y][x] = engine_snapshot_bd.last_drawing_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);
+}
index 807a9a14e5d238bc94504f08e80c5b1956a937ae..a6666d5d8c27cf07f13d1b776ebe420188a52434 100644 (file)
@@ -4314,7 +4314,7 @@ void InitElementPropertiesStatic(void)
     EL_BDX_BITER_UP,
     EL_BDX_BITER_LEFT,
     EL_BDX_BITER_DOWN,
     EL_BDX_BITER_UP,
     EL_BDX_BITER_LEFT,
     EL_BDX_BITER_DOWN,
-    EL_BDX_BLADDER,
+    EL_BDX_BUBBLE,
     EL_BDX_NUT,
     EL_EMC_MAGIC_BALL,
     EL_EMC_ANDROID,
     EL_BDX_NUT,
     EL_EMC_MAGIC_BALL,
     EL_EMC_ANDROID,
@@ -6752,6 +6752,9 @@ void OpenAll(void)
 
   DrawMainMenu();
 
 
   DrawMainMenu();
 
+  if (options.drop_file != NULL)
+    PushDropEvent(options.drop_file);
+
 #if 0
   Debug("internal:path", "SDL_GetBasePath() == '%s'",
        SDL_GetBasePath());
 #if 0
   Debug("internal:path", "SDL_GetBasePath() == '%s'",
        SDL_GetBasePath());
index 5e63c31f93307102d0b9903d12bf8aaebf722d25..6b4acba8d2830f0188d1447030a1f85e882664bc 100644 (file)
@@ -1222,6 +1222,9 @@ char *getStringCopyNStatic(const char *s, int n)
 
 char *getStringToUpper(const char *s)
 {
 
 char *getStringToUpper(const char *s)
 {
+  if (s == NULL)
+    return NULL;
+
   char *s_copy = checked_malloc(strlen(s) + 1);
   char *s_ptr = s_copy;
 
   char *s_copy = checked_malloc(strlen(s) + 1);
   char *s_ptr = s_copy;
 
@@ -1234,6 +1237,9 @@ char *getStringToUpper(const char *s)
 
 char *getStringToLower(const char *s)
 {
 
 char *getStringToLower(const char *s)
 {
+  if (s == NULL)
+    return NULL;
+
   char *s_copy = checked_malloc(strlen(s) + 1);
   char *s_ptr = s_copy;
 
   char *s_copy = checked_malloc(strlen(s) + 1);
   char *s_ptr = s_copy;
 
@@ -1704,6 +1710,7 @@ void GetOptions(int argc, char *argv[],
   options.player_name = NULL;
   options.identifier = NULL;
   options.level_nr = NULL;
   options.player_name = NULL;
   options.identifier = NULL;
   options.level_nr = NULL;
+  options.drop_file = NULL;
 
   options.display_nr = 0;
 
 
   options.display_nr = 0;
 
@@ -1870,6 +1877,15 @@ void GetOptions(int argc, char *argv[],
       if (option_arg == next_option)
        options_left++;
     }
       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;
     else if (strncmp(option, "-verbose", option_len) == 0)
     {
       options.verbose = TRUE;
index a19defa37acc5a7f7cc8cc07eeb958db0eafe973..d664eecc01df267ae8a86aff5f04e29cb43abbdc 100644 (file)
@@ -502,7 +502,7 @@ SDL_Surface *SDLCreateNativeSurface(int width, int height, int depth)
   return surface;
 }
 
   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;
 {
   int width  = surface->w;
   int height = surface->h;
@@ -522,11 +522,16 @@ Bitmap *SDLGetBitmapFromSurface(SDL_Surface *surface)
   if (!SDLHasAlpha(bitmap->surface_masked) &&
       !SDLHasColorKey(bitmap->surface_masked))
     SDL_SetColorKey(bitmap->surface_masked, SET_TRANSPARENT_PIXEL,
   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;
 }
 
 
   return bitmap;
 }
 
+Bitmap *SDLGetBitmapFromSurface(SDL_Surface *surface)
+{
+  return SDLGetBitmapFromSurface_WithMaskedColor(surface, 0x00, 0x00, 0x00);
+}
+
 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
 {
   if (program.headless)
 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
 {
   if (program.headless)
index bbbaa7675919640c264161d7f86a9a467b35669c..1545f6865fbc80317f3e53af68c6a6cf8b27da39 100644 (file)
@@ -400,6 +400,7 @@ const char *SDLGetRendererName(void);
 boolean SDLSetNativeSurface(SDL_Surface **);
 SDL_Surface *SDLGetNativeSurface(SDL_Surface *);
 SDL_Surface *SDLCreateNativeSurface(int, int, int);
 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 *);
 Bitmap *SDLGetBitmapFromSurface(SDL_Surface *);
 void SDLCreateBitmapTextures(Bitmap *);
 void SDLFreeBitmapTextures(Bitmap *);
index 4104a042e8d1d901404d03998280d938b26feb7b..fb63321bd2499bebec9a95c4dc63055f9bd6e30f 100644 (file)
@@ -797,26 +797,68 @@ char *getEditorSetupFilename(void)
   return filename;
 }
 
   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;
 
   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;
 }
 
 
   return filename;
 }
 
-char *getHelpTextFilename(void)
+static char *getHelpFilename(char *basename)
 {
   static char *filename = NULL;
 
   checked_free(filename);
 
 {
   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)
 }
 
 static char *getLevelSetInfoBasename(int nr)
index c7a5330267f819b55ac46af771399ed01885d1d7..5692c9da39e56c5c035563ca569f860335c841db 100644 (file)
@@ -279,6 +279,7 @@ char *getSetupFilename(void);
 char *getDefaultSetupFilename(void);
 char *getPlatformSetupFilename(void);
 char *getEditorSetupFilename(void);
 char *getDefaultSetupFilename(void);
 char *getPlatformSetupFilename(void);
 char *getEditorSetupFilename(void);
+char *getFilenameFromCurrentLevelDirUpward(char *);
 char *getHelpAnimFilename(void);
 char *getHelpTextFilename(void);
 char *getLevelSetInfoFilename(int);
 char *getHelpAnimFilename(void);
 char *getHelpTextFilename(void);
 char *getLevelSetInfoFilename(int);
index a1f009f77c8470f5d0b7e0fcbe85eb97db53ecd0..e77e6fe67bfede76ebdcf56b619f281172bea158 100644 (file)
@@ -1843,6 +1843,28 @@ void PushUserEvent(int code, int value1, int value2)
   SDL_PushEvent((SDL_Event *)&event);
 }
 
   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())
 boolean PendingEscapeKeyEvent(void)
 {
   if (PendingEvent())
index dc6d0f363d69f438b6e4c52cbafb2e8a5508eea2..85c26a5f34fd84c1b50939b92bf603fff89972cb 100644 (file)
@@ -1063,6 +1063,8 @@ struct OptionInfo
   char *identifier;
   char *level_nr;
 
   char *identifier;
   char *level_nr;
 
+  char *drop_file;
+
   int display_nr;
 
   boolean mytapes;
   int display_nr;
 
   boolean mytapes;
@@ -1320,6 +1322,7 @@ struct SetupEditorInfo
   boolean el_by_type;
 
   boolean show_element_token;
   boolean el_by_type;
 
   boolean show_element_token;
+  boolean fast_game_start;
 
   boolean show_read_only_warning;
 
 
   boolean show_read_only_warning;
 
@@ -1528,7 +1531,7 @@ struct SetupInfo
   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_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;
   int bd_palette_c64;
   int bd_palette_c64dtv;
   int bd_palette_atari;
@@ -2058,6 +2061,7 @@ KeyMod GetKeyModStateFromEvents(void);
 void StartTextInput(int, int, int, int);
 void StopTextInput(void);
 void PushUserEvent(int, int, int);
 void StartTextInput(int, int, int, int);
 void StopTextInput(void);
 void PushUserEvent(int, int, int);
+void PushDropEvent(char *);
 boolean PendingEscapeKeyEvent(void);
 
 void InitJoysticks(void);
 boolean PendingEscapeKeyEvent(void);
 
 void InitJoysticks(void);
index 446a873b23dcfd9c137ed1792b1399f1525ed1d6..1db4848f0170a0964414be29d4b64c784d13a3b3 100644 (file)
@@ -589,8 +589,8 @@ static int DrawTextBufferExt(int x, int y, char *text_buffer, int base_font_nr,
     {
       if ((line[i] = *text_buffer++) == '\n')
       {
     {
       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;
          text_buffer--;
 
        break;
index 0aa6347ac4106620b6c3d3aa851dd5b7f08e57ec..5a31fcbfdfb6ae598eed85bfe6c9ec6891baf21d 100644 (file)
@@ -121,7 +121,11 @@ static voidpf ZCALLBACK fopen64_file_func(ZIP_UNUSED voidpf opaque, const void *
 
     if ((filename != NULL) && (mode_fopen != NULL))
     {
 
     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;
         return file_build_ioposix(file, (const char*)filename);
     }
     return file;
index 8ab7313dba3a77667264417e627d886e78cd1035..0375a9c5457be79665d190ad7eefa08d970f4efc 100644 (file)
@@ -6549,17 +6549,17 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   },
   {
     "bdx_wall_key_1",
   },
   {
     "bdx_wall_key_1",
-    "bdx_wall",
+    "bdx_wall_key",
     "Wall with key 1"
   },
   {
     "bdx_wall_key_2",
     "Wall with key 1"
   },
   {
     "bdx_wall_key_2",
-    "bdx_wall",
+    "bdx_wall_key",
     "Wall with key 2"
   },
   {
     "bdx_wall_key_3",
     "Wall with key 2"
   },
   {
     "bdx_wall_key_3",
-    "bdx_wall",
+    "bdx_wall_key",
     "Wall with key 3"
   },
   {
     "Wall with key 3"
   },
   {
@@ -6718,14 +6718,14 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "Amoeba 2"
   },
   {
     "Amoeba 2"
   },
   {
-    "bdx_bladder",
-    "bdx_bladder",
-    "Bladder"
+    "bdx_bubble",
+    "bdx_bubble",
+    "Bubble"
   },
   {
   },
   {
-    "bdx_bladder_spender",
-    "bdx_bladder_spender",
-    "Bladder spender"
+    "bdx_trapped_bubble",
+    "bdx_trapped_bubble",
+    "Trapped bubble"
   },
   {
     "bdx_creature_switch",
   },
   {
     "bdx_creature_switch",
@@ -7403,44 +7403,44 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "Enclosed cow (7)"
   },
   {
     "Enclosed cow (7)"
   },
   {
-    "bdx_bladder_1",
-    "bdx_bladder",
-    "Bladder (1)"
+    "bdx_bubble_1",
+    "bdx_bubble",
+    "Bubble (1)"
   },
   {
   },
   {
-    "bdx_bladder_2",
-    "bdx_bladder",
-    "Bladder (2)"
+    "bdx_bubble_2",
+    "bdx_bubble",
+    "Bubble (2)"
   },
   {
   },
   {
-    "bdx_bladder_3",
-    "bdx_bladder",
-    "Bladder (3)"
+    "bdx_bubble_3",
+    "bdx_bubble",
+    "Bubble (3)"
   },
   {
   },
   {
-    "bdx_bladder_4",
-    "bdx_bladder",
-    "Bladder (4)"
+    "bdx_bubble_4",
+    "bdx_bubble",
+    "Bubble (4)"
   },
   {
   },
   {
-    "bdx_bladder_5",
-    "bdx_bladder",
-    "Bladder (5)"
+    "bdx_bubble_5",
+    "bdx_bubble",
+    "Bubble (5)"
   },
   {
   },
   {
-    "bdx_bladder_6",
-    "bdx_bladder",
-    "Bladder (6)"
+    "bdx_bubble_6",
+    "bdx_bubble",
+    "Bubble (6)"
   },
   {
   },
   {
-    "bdx_bladder_7",
-    "bdx_bladder",
-    "Bladder (7)"
+    "bdx_bubble_7",
+    "bdx_bubble",
+    "Bubble (7)"
   },
   {
   },
   {
-    "bdx_bladder_8",
-    "bdx_bladder",
-    "Bladder (8)"
+    "bdx_bubble_8",
+    "bdx_bubble",
+    "Bubble (8)"
   },
   {
     "bdx_player.growing_1",
   },
   {
     "bdx_player.growing_1",
@@ -9062,6 +9062,7 @@ static void print_usage(void)
        "  -g, --graphics DIRECTORY         alternative graphics DIRECTORY\n"
        "  -s, --sounds DIRECTORY           alternative sounds DIRECTORY\n"
        "  -m, --music DIRECTORY            alternative music DIRECTORY\n"
        "  -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"
        "      --display NR                 open program window on display NR\n"
        "      --mytapes                    use private tapes for tape tests\n"
        "  -n, --network                    network multiplayer game\n"
index 309229ee71c2fdce7670c5e19f65792c4ae6e009..0deb4de8e5fac2ef3f84c8f3084eeb8cf9c888be 100644 (file)
@@ -34,8 +34,6 @@
 
 #define IMG_UNDEFINED                  (-1)
 #define IMG_EMPTY                      IMG_EMPTY_SPACE
 
 #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 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_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 EL_DF_CELL                             (EL_DF_START2 + 305)
 #define EL_DF_MINE                             (EL_DF_START2 + 306)
 #define EL_DF_REFRACTOR                                (EL_DF_START2 + 307)
 #define EL_BDX_NUT                             1301
 #define EL_BDX_AMOEBA_1                                1302
 #define EL_BDX_AMOEBA_2                                1303
 #define EL_BDX_NUT                             1301
 #define EL_BDX_AMOEBA_1                                1302
 #define EL_BDX_AMOEBA_2                                1303
-#define EL_BDX_BLADDER                         1304
-#define EL_BDX_BLADDER_SPENDER                 1305
+#define EL_BDX_BUBBLE                          1304
+#define EL_BDX_TRAPPED_BUBBLE                  1305
 #define EL_BDX_CREATURE_SWITCH                 1306
 #define EL_BDX_CREATURE_SWITCH_ACTIVE          1307
 #define EL_BDX_BITER_SWITCH_1                  1308
 #define EL_BDX_CREATURE_SWITCH                 1306
 #define EL_BDX_CREATURE_SWITCH_ACTIVE          1307
 #define EL_BDX_BITER_SWITCH_1                  1308
 #define EL_BDX_COW_ENCLOSED_5                  1438
 #define EL_BDX_COW_ENCLOSED_6                  1439
 #define EL_BDX_COW_ENCLOSED_7                  1440
 #define EL_BDX_COW_ENCLOSED_5                  1438
 #define EL_BDX_COW_ENCLOSED_6                  1439
 #define EL_BDX_COW_ENCLOSED_7                  1440
-#define EL_BDX_BLADDER_1                       1441
-#define EL_BDX_BLADDER_2                       1442
-#define EL_BDX_BLADDER_3                       1443
-#define EL_BDX_BLADDER_4                       1444
-#define EL_BDX_BLADDER_5                       1445
-#define EL_BDX_BLADDER_6                       1446
-#define EL_BDX_BLADDER_7                       1447
-#define EL_BDX_BLADDER_8                       1448
+#define EL_BDX_BUBBLE_1                                1441
+#define EL_BDX_BUBBLE_2                                1442
+#define EL_BDX_BUBBLE_3                                1443
+#define EL_BDX_BUBBLE_4                                1444
+#define EL_BDX_BUBBLE_5                                1445
+#define EL_BDX_BUBBLE_6                                1446
+#define EL_BDX_BUBBLE_7                                1447
+#define EL_BDX_BUBBLE_8                                1448
 #define EL_BDX_PLAYER_GROWING_1                        1449
 #define EL_BDX_PLAYER_GROWING_2                        1450
 #define EL_BDX_PLAYER_GROWING_3                        1451
 #define EL_BDX_PLAYER_GROWING_1                        1449
 #define EL_BDX_PLAYER_GROWING_2                        1450
 #define EL_BDX_PLAYER_GROWING_3                        1451
@@ -3023,7 +3022,7 @@ enum
 #define PROGRAM_VERSION_MAJOR          4
 #define PROGRAM_VERSION_MINOR          0
 #define PROGRAM_VERSION_PATCH          0
 #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-3"
 
 #define PROGRAM_TITLE_STRING           "Rocks'n'Diamonds"
 #define PROGRAM_AUTHOR_STRING          "Holger Schemel"
 
 #define PROGRAM_TITLE_STRING           "Rocks'n'Diamonds"
 #define PROGRAM_AUTHOR_STRING          "Holger Schemel"
@@ -3754,7 +3753,7 @@ struct LevelInfo
   int bd_acid_turns_to_element;                // BD acid target element after spreading
   int bd_biter_move_delay;             // BD biter delay between movements (in BD frames)
   int bd_biter_eats_element;           // BD biter eats this game element when moving
   int bd_acid_turns_to_element;                // BD acid target element after spreading
   int bd_biter_move_delay;             // BD biter delay between movements (in BD frames)
   int bd_biter_eats_element;           // BD biter eats this game element when moving
-  int bd_bladder_converts_by_element;  // BD bladder converts to clock by touching this element
+  int bd_bubble_converts_by_element;   // BD bubble converts to clock by touching this element
   boolean bd_change_expanding_wall;    // BD expanding wall direction is changed if enabled
   boolean bd_replicators_active;       // BD replicators start in active state if enabled
   int bd_replicator_create_delay;      // BD replicator delay between replications (in BD frames)
   boolean bd_change_expanding_wall;    // BD expanding wall direction is changed if enabled
   boolean bd_replicators_active;       // BD replicators start in active state if enabled
   int bd_replicator_create_delay;      // BD replicator delay between replications (in BD frames)
index a31e6121f4dd28b255bf69843a11cff503a0ce54..e52fbea6c2158130cd8b0d5e175db8284d4d17d0 100644 (file)
@@ -4715,9 +4715,6 @@ static void DrawChooseTree(TreeInfo **ti_ptr)
 
   UnmapAllGadgets();
 
 
   UnmapAllGadgets();
 
-  FreeScreenGadgets();
-  CreateScreenGadgets();
-
   if (restart_music)
     FadeMenuSoundsAndMusic();
 
   if (restart_music)
     FadeMenuSoundsAndMusic();
 
@@ -4735,6 +4732,9 @@ static void DrawChooseTree(TreeInfo **ti_ptr)
   else if (game_status == GAME_MODE_SCORES)
     SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
 
   else if (game_status == GAME_MODE_SCORES)
     SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
 
+  FreeScreenGadgets();
+  CreateScreenGadgets();
+
   ClearField();
 
   OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
   ClearField();
 
   OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
@@ -7991,9 +7991,9 @@ static struct TokenInfo setup_info_engines[] =
   { 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_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,           ""                              },
   { TYPE_SWITCH,       &setup.bd_show_invisible_outbox,"Show invisible outbox:"        },
   { TYPE_ENTER_LIST,   &execSetupChoosePaletteC64,     "Color Palette (C64):"          },
   { TYPE_STRING,       &bd_palette_c64_text,           ""                              },
@@ -8038,7 +8038,7 @@ static struct TokenInfo setup_info_editor[] =
 #if 0
   { TYPE_SWITCH,       &setup.editor.el_headlines,     "Headlines:"                    },
 #endif
 #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_dynamic,       "Dynamic level elements:"       },
   { TYPE_EMPTY,                NULL,                           ""                              },
 #if 0
@@ -8046,9 +8046,10 @@ static struct TokenInfo setup_info_editor[] =
   { TYPE_SWITCH,       &setup.editor.el_by_type,       "Show elements by type:"        },
   { TYPE_EMPTY,                NULL,                           ""                              },
 #endif
   { 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_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"                          },
 
   { TYPE_EMPTY,                NULL,                           ""                              },
   { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
 
index 1881220a079c35dc07baa93eb65611af9040a447..09933f1d4bc3507a0fca7eda48ac16259ff68254 100644 (file)
@@ -6354,7 +6354,7 @@ bd_object_mapping_list[] =
   },
   {
     O_BLADDER_SPENDER,                         TRUE,
   },
   {
     O_BLADDER_SPENDER,                         TRUE,
-    EL_BDX_BLADDER_SPENDER,                    -1, -1
+    EL_BDX_TRAPPED_BUBBLE,                     -1, -1
   },
   {
     O_INBOX,                                   TRUE,
   },
   {
     O_INBOX,                                   TRUE,
@@ -6762,71 +6762,71 @@ bd_object_mapping_list[] =
   },
   {
     O_BLADDER,                                 TRUE,
   },
   {
     O_BLADDER,                                 TRUE,
-    EL_BDX_BLADDER,                            -1, -1
+    EL_BDX_BUBBLE,                             -1, -1
   },
   {
     O_BLADDER_1,                               TRUE,
   },
   {
     O_BLADDER_1,                               TRUE,
-    EL_BDX_BLADDER_1,                          -1, -1
+    EL_BDX_BUBBLE_1,                           -1, -1
   },
   {
     O_BLADDER_1,                               FALSE,
   },
   {
     O_BLADDER_1,                               FALSE,
-    EL_BDX_BLADDER,                            -1, -1
+    EL_BDX_BUBBLE,                             -1, -1
   },
   {
     O_BLADDER_2,                               TRUE,
   },
   {
     O_BLADDER_2,                               TRUE,
-    EL_BDX_BLADDER_2,                          -1, -1
+    EL_BDX_BUBBLE_2,                           -1, -1
   },
   {
     O_BLADDER_2,                               FALSE,
   },
   {
     O_BLADDER_2,                               FALSE,
-    EL_BDX_BLADDER,                            -1, -1
+    EL_BDX_BUBBLE,                             -1, -1
   },
   {
     O_BLADDER_3,                               TRUE,
   },
   {
     O_BLADDER_3,                               TRUE,
-    EL_BDX_BLADDER_3,                          -1, -1
+    EL_BDX_BUBBLE_3,                           -1, -1
   },
   {
     O_BLADDER_3,                               FALSE,
   },
   {
     O_BLADDER_3,                               FALSE,
-    EL_BDX_BLADDER,                            -1, -1
+    EL_BDX_BUBBLE,                             -1, -1
   },
   {
     O_BLADDER_4,                               TRUE,
   },
   {
     O_BLADDER_4,                               TRUE,
-    EL_BDX_BLADDER_4,                          -1, -1
+    EL_BDX_BUBBLE_4,                           -1, -1
   },
   {
     O_BLADDER_4,                               FALSE,
   },
   {
     O_BLADDER_4,                               FALSE,
-    EL_BDX_BLADDER,                            -1, -1
+    EL_BDX_BUBBLE,                             -1, -1
   },
   {
     O_BLADDER_5,                               TRUE,
   },
   {
     O_BLADDER_5,                               TRUE,
-    EL_BDX_BLADDER_5,                          -1, -1
+    EL_BDX_BUBBLE_5,                           -1, -1
   },
   {
     O_BLADDER_5,                               FALSE,
   },
   {
     O_BLADDER_5,                               FALSE,
-    EL_BDX_BLADDER,                            -1, -1
+    EL_BDX_BUBBLE,                             -1, -1
   },
   {
     O_BLADDER_6,                               TRUE,
   },
   {
     O_BLADDER_6,                               TRUE,
-    EL_BDX_BLADDER_6,                          -1, -1
+    EL_BDX_BUBBLE_6,                           -1, -1
   },
   {
     O_BLADDER_6,                               FALSE,
   },
   {
     O_BLADDER_6,                               FALSE,
-    EL_BDX_BLADDER,                            -1, -1
+    EL_BDX_BUBBLE,                             -1, -1
   },
   {
     O_BLADDER_7,                               TRUE,
   },
   {
     O_BLADDER_7,                               TRUE,
-    EL_BDX_BLADDER_7,                          -1, -1
+    EL_BDX_BUBBLE_7,                           -1, -1
   },
   {
     O_BLADDER_7,                               FALSE,
   },
   {
     O_BLADDER_7,                               FALSE,
-    EL_BDX_BLADDER,                            -1, -1
+    EL_BDX_BUBBLE,                             -1, -1
   },
   {
     O_BLADDER_8,                               TRUE,
   },
   {
     O_BLADDER_8,                               TRUE,
-    EL_BDX_BLADDER_8,                          -1, -1
+    EL_BDX_BUBBLE_8,                           -1, -1
   },
   {
     O_BLADDER_8,                               FALSE,
   },
   {
     O_BLADDER_8,                               FALSE,
-    EL_BDX_BLADDER,                            -1, -1
+    EL_BDX_BUBBLE,                             -1, -1
   },
   {
     O_WAITING_STONE,                           TRUE,
   },
   {
     O_WAITING_STONE,                           TRUE,
@@ -7686,6 +7686,9 @@ int map_element_BD_to_RND_cave(int element_bd)
     mapping_initialized = TRUE;
   }
 
     mapping_initialized = TRUE;
   }
 
+  // always map (scanned) run-time elements to normal elements
+  element_bd &= O_MASK;
+
   if (element_bd < 0 || element_bd >= O_MAX_ALL)
   {
     Warn("invalid BD element %d", element_bd);
   if (element_bd < 0 || element_bd >= O_MAX_ALL)
   {
     Warn("invalid BD element %d", element_bd);
@@ -7716,6 +7719,9 @@ int map_element_BD_to_RND_game(int element_bd)
     mapping_initialized = TRUE;
   }
 
     mapping_initialized = TRUE;
   }
 
+  // always map (scanned) run-time elements to normal elements
+  element_bd &= O_MASK;
+
   if (element_bd < 0 || element_bd >= O_MAX_ALL)
   {
     Warn("invalid BD element %d", element_bd);
   if (element_bd < 0 || element_bd >= O_MAX_ALL)
   {
     Warn("invalid BD element %d", element_bd);
@@ -11215,6 +11221,26 @@ void InitGraphicInfo_EM(void)
   }
 }
 
   }
 }
 
+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,
 static void CheckSaveEngineSnapshot_EM(int frame,
                                       boolean any_player_moving,
                                       boolean any_player_snapping,
@@ -11272,6 +11298,19 @@ static void CheckSaveEngineSnapshot_MM(boolean element_clicked,
   }
 }
 
   }
 }
 
+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,
 boolean CheckSingleStepMode_EM(int frame,
                               boolean any_player_moving,
                               boolean any_player_snapping,